@vyuhlabs/dxkit 2.4.5 → 2.4.7
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/CHANGELOG.md +1022 -0
- package/README.md +160 -45
- package/dist/analysis-result.d.ts +112 -0
- package/dist/analysis-result.d.ts.map +1 -0
- package/dist/analysis-result.js +52 -0
- package/dist/analysis-result.js.map +1 -0
- package/dist/analyzers/bom/detailed.d.ts.map +1 -1
- package/dist/analyzers/bom/detailed.js +19 -0
- package/dist/analyzers/bom/detailed.js.map +1 -1
- package/dist/analyzers/bom/gather.d.ts +27 -26
- package/dist/analyzers/bom/gather.d.ts.map +1 -1
- package/dist/analyzers/bom/gather.js +26 -87
- package/dist/analyzers/bom/gather.js.map +1 -1
- package/dist/analyzers/bom/index.d.ts +0 -7
- package/dist/analyzers/bom/index.d.ts.map +1 -1
- package/dist/analyzers/bom/index.js +98 -48
- package/dist/analyzers/bom/index.js.map +1 -1
- package/dist/analyzers/bom/types.d.ts +11 -13
- package/dist/analyzers/bom/types.d.ts.map +1 -1
- package/dist/analyzers/cache.d.ts +95 -0
- package/dist/analyzers/cache.d.ts.map +1 -0
- package/dist/analyzers/cache.js +309 -0
- package/dist/analyzers/cache.js.map +1 -0
- package/dist/analyzers/coverage-runner.d.ts +56 -0
- package/dist/analyzers/coverage-runner.d.ts.map +1 -0
- package/dist/analyzers/coverage-runner.js +72 -0
- package/dist/analyzers/coverage-runner.js.map +1 -0
- package/dist/analyzers/dashboard/index.d.ts +24 -0
- package/dist/analyzers/dashboard/index.d.ts.map +1 -0
- package/dist/analyzers/dashboard/index.js +666 -0
- package/dist/analyzers/dashboard/index.js.map +1 -0
- package/dist/analyzers/developer/gather.d.ts.map +1 -1
- package/dist/analyzers/developer/gather.js +205 -37
- package/dist/analyzers/developer/gather.js.map +1 -1
- package/dist/analyzers/developer/index.d.ts +1 -1
- package/dist/analyzers/developer/index.d.ts.map +1 -1
- package/dist/analyzers/developer/index.js +19 -8
- package/dist/analyzers/developer/index.js.map +1 -1
- package/dist/analyzers/dispatcher.d.ts +37 -0
- package/dist/analyzers/dispatcher.d.ts.map +1 -1
- package/dist/analyzers/dispatcher.js +56 -9
- package/dist/analyzers/dispatcher.js.map +1 -1
- package/dist/analyzers/docs/shallow.d.ts +17 -5
- package/dist/analyzers/docs/shallow.d.ts.map +1 -1
- package/dist/analyzers/docs/shallow.js +65 -2
- package/dist/analyzers/docs/shallow.js.map +1 -1
- package/dist/analyzers/dx/shallow.d.ts +17 -5
- package/dist/analyzers/dx/shallow.d.ts.map +1 -1
- package/dist/analyzers/dx/shallow.js +66 -2
- package/dist/analyzers/dx/shallow.js.map +1 -1
- package/dist/analyzers/health/actions.d.ts +1 -1
- package/dist/analyzers/health/actions.d.ts.map +1 -1
- package/dist/analyzers/health/actions.js +27 -9
- package/dist/analyzers/health/actions.js.map +1 -1
- package/dist/analyzers/health/detailed.d.ts +2 -1
- package/dist/analyzers/health/detailed.d.ts.map +1 -1
- package/dist/analyzers/health/detailed.js +11 -7
- package/dist/analyzers/health/detailed.js.map +1 -1
- package/dist/analyzers/health.d.ts +27 -0
- package/dist/analyzers/health.d.ts.map +1 -1
- package/dist/analyzers/health.js +271 -33
- package/dist/analyzers/health.js.map +1 -1
- package/dist/analyzers/licenses/gather.d.ts +35 -8
- package/dist/analyzers/licenses/gather.d.ts.map +1 -1
- package/dist/analyzers/licenses/gather.js +70 -13
- package/dist/analyzers/licenses/gather.js.map +1 -1
- package/dist/analyzers/licenses/index.d.ts +1 -1
- package/dist/analyzers/licenses/index.d.ts.map +1 -1
- package/dist/analyzers/licenses/index.js +52 -11
- package/dist/analyzers/licenses/index.js.map +1 -1
- package/dist/analyzers/licenses/types.d.ts +15 -0
- package/dist/analyzers/licenses/types.d.ts.map +1 -1
- package/dist/analyzers/maintainability/shallow.d.ts +17 -5
- package/dist/analyzers/maintainability/shallow.d.ts.map +1 -1
- package/dist/analyzers/maintainability/shallow.js +80 -2
- package/dist/analyzers/maintainability/shallow.js.map +1 -1
- package/dist/analyzers/quality/detailed.d.ts.map +1 -1
- package/dist/analyzers/quality/detailed.js +4 -6
- package/dist/analyzers/quality/detailed.js.map +1 -1
- package/dist/analyzers/quality/gather.d.ts +1 -14
- package/dist/analyzers/quality/gather.d.ts.map +1 -1
- package/dist/analyzers/quality/gather.js +48 -137
- package/dist/analyzers/quality/gather.js.map +1 -1
- package/dist/analyzers/quality/index.d.ts +9 -2
- package/dist/analyzers/quality/index.d.ts.map +1 -1
- package/dist/analyzers/quality/index.js +189 -117
- package/dist/analyzers/quality/index.js.map +1 -1
- package/dist/analyzers/quality/shallow.d.ts +50 -5
- package/dist/analyzers/quality/shallow.d.ts.map +1 -1
- package/dist/analyzers/quality/shallow.js +155 -2
- package/dist/analyzers/quality/shallow.js.map +1 -1
- package/dist/analyzers/quality/types.d.ts +14 -0
- package/dist/analyzers/quality/types.d.ts.map +1 -1
- package/dist/analyzers/security/actions.d.ts +11 -4
- package/dist/analyzers/security/actions.d.ts.map +1 -1
- package/dist/analyzers/security/actions.js +87 -37
- package/dist/analyzers/security/actions.js.map +1 -1
- package/dist/analyzers/security/aggregator.d.ts +236 -0
- package/dist/analyzers/security/aggregator.d.ts.map +1 -0
- package/dist/analyzers/security/aggregator.js +347 -0
- package/dist/analyzers/security/aggregator.js.map +1 -0
- package/dist/analyzers/security/detailed.d.ts +2 -2
- package/dist/analyzers/security/detailed.d.ts.map +1 -1
- package/dist/analyzers/security/detailed.js +10 -9
- package/dist/analyzers/security/detailed.js.map +1 -1
- package/dist/analyzers/security/gather.d.ts +103 -1
- package/dist/analyzers/security/gather.d.ts.map +1 -1
- package/dist/analyzers/security/gather.js +281 -9
- package/dist/analyzers/security/gather.js.map +1 -1
- package/dist/analyzers/security/index.d.ts +15 -0
- package/dist/analyzers/security/index.d.ts.map +1 -1
- package/dist/analyzers/security/index.js +463 -50
- package/dist/analyzers/security/index.js.map +1 -1
- package/dist/analyzers/security/shallow.d.ts +50 -6
- package/dist/analyzers/security/shallow.d.ts.map +1 -1
- package/dist/analyzers/security/shallow.js +154 -2
- package/dist/analyzers/security/shallow.js.map +1 -1
- package/dist/analyzers/security/types.d.ts +51 -0
- package/dist/analyzers/security/types.d.ts.map +1 -1
- package/dist/analyzers/tests/detailed.d.ts.map +1 -1
- package/dist/analyzers/tests/detailed.js +2 -3
- package/dist/analyzers/tests/detailed.js.map +1 -1
- package/dist/analyzers/tests/gather.d.ts +2 -1
- package/dist/analyzers/tests/gather.d.ts.map +1 -1
- package/dist/analyzers/tests/gather.js +98 -69
- package/dist/analyzers/tests/gather.js.map +1 -1
- package/dist/analyzers/tests/index.d.ts +11 -2
- package/dist/analyzers/tests/index.d.ts.map +1 -1
- package/dist/analyzers/tests/index.js +85 -18
- package/dist/analyzers/tests/index.js.map +1 -1
- package/dist/analyzers/tests/shallow.d.ts +19 -5
- package/dist/analyzers/tests/shallow.d.ts.map +1 -1
- package/dist/analyzers/tests/shallow.js +89 -2
- package/dist/analyzers/tests/shallow.js.map +1 -1
- package/dist/analyzers/tests/types.d.ts +41 -1
- package/dist/analyzers/tests/types.d.ts.map +1 -1
- package/dist/analyzers/tools/autogen-header.d.ts +8 -0
- package/dist/analyzers/tools/autogen-header.d.ts.map +1 -0
- package/dist/analyzers/tools/autogen-header.js +107 -0
- package/dist/analyzers/tools/autogen-header.js.map +1 -0
- package/dist/analyzers/tools/cloc.d.ts.map +1 -1
- package/dist/analyzers/tools/cloc.js +36 -5
- package/dist/analyzers/tools/cloc.js.map +1 -1
- package/dist/analyzers/tools/coverage.d.ts +1 -1
- package/dist/analyzers/tools/coverage.d.ts.map +1 -1
- package/dist/analyzers/tools/coverage.js.map +1 -1
- package/dist/analyzers/tools/debug-statements.d.ts +17 -0
- package/dist/analyzers/tools/debug-statements.d.ts.map +1 -0
- package/dist/analyzers/tools/debug-statements.js +58 -0
- package/dist/analyzers/tools/debug-statements.js.map +1 -0
- package/dist/analyzers/tools/default-exclusions.gitignore +28 -0
- package/dist/analyzers/tools/exclusions.d.ts +33 -6
- package/dist/analyzers/tools/exclusions.d.ts.map +1 -1
- package/dist/analyzers/tools/exclusions.js +95 -26
- package/dist/analyzers/tools/exclusions.js.map +1 -1
- package/dist/analyzers/tools/generic.d.ts +17 -2
- package/dist/analyzers/tools/generic.d.ts.map +1 -1
- package/dist/analyzers/tools/generic.js +206 -109
- package/dist/analyzers/tools/generic.js.map +1 -1
- package/dist/analyzers/tools/gitleaks.d.ts.map +1 -1
- package/dist/analyzers/tools/gitleaks.js +48 -1
- package/dist/analyzers/tools/gitleaks.js.map +1 -1
- package/dist/analyzers/tools/graphify.d.ts +30 -2
- package/dist/analyzers/tools/graphify.d.ts.map +1 -1
- package/dist/analyzers/tools/graphify.js +131 -15
- package/dist/analyzers/tools/graphify.js.map +1 -1
- package/dist/analyzers/tools/jscpd.d.ts +12 -2
- package/dist/analyzers/tools/jscpd.d.ts.map +1 -1
- package/dist/analyzers/tools/jscpd.js +129 -6
- package/dist/analyzers/tools/jscpd.js.map +1 -1
- package/dist/analyzers/tools/minified-detection.d.ts +9 -0
- package/dist/analyzers/tools/minified-detection.d.ts.map +1 -0
- package/dist/analyzers/tools/minified-detection.js +147 -0
- package/dist/analyzers/tools/minified-detection.js.map +1 -0
- package/dist/analyzers/tools/nuget-package-reference.d.ts +131 -0
- package/dist/analyzers/tools/nuget-package-reference.d.ts.map +1 -0
- package/dist/analyzers/tools/nuget-package-reference.js +175 -0
- package/dist/analyzers/tools/nuget-package-reference.js.map +1 -0
- package/dist/analyzers/tools/osv-scanner-deps.d.ts +48 -0
- package/dist/analyzers/tools/osv-scanner-deps.d.ts.map +1 -0
- package/dist/analyzers/tools/{osv-scanner-maven.js → osv-scanner-deps.js} +78 -46
- package/dist/analyzers/tools/osv-scanner-deps.js.map +1 -0
- package/dist/analyzers/tools/osv.d.ts +36 -0
- package/dist/analyzers/tools/osv.d.ts.map +1 -1
- package/dist/analyzers/tools/osv.js +26 -0
- package/dist/analyzers/tools/osv.js.map +1 -1
- package/dist/analyzers/tools/parallel.d.ts +1 -1
- package/dist/analyzers/tools/parallel.d.ts.map +1 -1
- package/dist/analyzers/tools/parallel.js +2 -2
- package/dist/analyzers/tools/parallel.js.map +1 -1
- package/dist/analyzers/tools/risk-score.d.ts +7 -0
- package/dist/analyzers/tools/risk-score.d.ts.map +1 -1
- package/dist/analyzers/tools/risk-score.js +9 -2
- package/dist/analyzers/tools/risk-score.js.map +1 -1
- package/dist/analyzers/tools/run-tests-helper.d.ts +43 -0
- package/dist/analyzers/tools/run-tests-helper.d.ts.map +1 -0
- package/dist/analyzers/tools/run-tests-helper.js +156 -0
- package/dist/analyzers/tools/run-tests-helper.js.map +1 -0
- package/dist/analyzers/tools/runner.d.ts.map +1 -1
- package/dist/analyzers/tools/runner.js +75 -12
- package/dist/analyzers/tools/runner.js.map +1 -1
- package/dist/analyzers/tools/semgrep.d.ts +39 -2
- package/dist/analyzers/tools/semgrep.d.ts.map +1 -1
- package/dist/analyzers/tools/semgrep.js +131 -9
- package/dist/analyzers/tools/semgrep.js.map +1 -1
- package/dist/analyzers/tools/timing.d.ts +17 -3
- package/dist/analyzers/tools/timing.d.ts.map +1 -1
- package/dist/analyzers/tools/timing.js +36 -14
- package/dist/analyzers/tools/timing.js.map +1 -1
- package/dist/analyzers/tools/tool-registry.d.ts +10 -0
- package/dist/analyzers/tools/tool-registry.d.ts.map +1 -1
- package/dist/analyzers/tools/tool-registry.js +120 -1
- package/dist/analyzers/tools/tool-registry.js.map +1 -1
- package/dist/analyzers/tools/tools-unavailable-prose.d.ts +18 -0
- package/dist/analyzers/tools/tools-unavailable-prose.d.ts.map +1 -0
- package/dist/analyzers/tools/tools-unavailable-prose.js +69 -0
- package/dist/analyzers/tools/tools-unavailable-prose.js.map +1 -0
- package/dist/analyzers/tools/upgrade-plan-resolver.d.ts.map +1 -1
- package/dist/analyzers/tools/upgrade-plan-resolver.js +7 -0
- package/dist/analyzers/tools/upgrade-plan-resolver.js.map +1 -1
- package/dist/analyzers/tools/vendored-advisor.d.ts +43 -0
- package/dist/analyzers/tools/vendored-advisor.d.ts.map +1 -0
- package/dist/analyzers/tools/vendored-advisor.js +107 -0
- package/dist/analyzers/tools/vendored-advisor.js.map +1 -0
- package/dist/analyzers/tools/walk-paths.d.ts +78 -0
- package/dist/analyzers/tools/walk-paths.d.ts.map +1 -0
- package/dist/analyzers/tools/walk-paths.js +150 -0
- package/dist/analyzers/tools/walk-paths.js.map +1 -0
- package/dist/analyzers/tools/walk-source-files.d.ts +70 -0
- package/dist/analyzers/tools/walk-source-files.d.ts.map +1 -0
- package/dist/analyzers/tools/walk-source-files.js +369 -0
- package/dist/analyzers/tools/walk-source-files.js.map +1 -0
- package/dist/analyzers/types.d.ts +204 -4
- package/dist/analyzers/types.d.ts.map +1 -1
- package/dist/analyzers/xlsx/bom.d.ts.map +1 -1
- package/dist/analyzers/xlsx/bom.js +8 -1
- package/dist/analyzers/xlsx/bom.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +557 -189
- package/dist/cli.js.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js +24 -7
- package/dist/detect.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +103 -53
- package/dist/doctor.js.map +1 -1
- package/dist/languages/capabilities/provider.d.ts +130 -1
- package/dist/languages/capabilities/provider.d.ts.map +1 -1
- package/dist/languages/capabilities/types.d.ts +68 -7
- package/dist/languages/capabilities/types.d.ts.map +1 -1
- package/dist/languages/csharp.d.ts +15 -1
- package/dist/languages/csharp.d.ts.map +1 -1
- package/dist/languages/csharp.js +624 -146
- package/dist/languages/csharp.js.map +1 -1
- package/dist/languages/go.d.ts.map +1 -1
- package/dist/languages/go.js +89 -11
- package/dist/languages/go.js.map +1 -1
- package/dist/languages/index.d.ts +131 -2
- package/dist/languages/index.d.ts.map +1 -1
- package/dist/languages/index.js +208 -0
- package/dist/languages/index.js.map +1 -1
- package/dist/languages/java.d.ts.map +1 -1
- package/dist/languages/java.js +121 -32
- package/dist/languages/java.js.map +1 -1
- package/dist/languages/kotlin.d.ts.map +1 -1
- package/dist/languages/kotlin.js +140 -32
- package/dist/languages/kotlin.js.map +1 -1
- package/dist/languages/python.d.ts.map +1 -1
- package/dist/languages/python.js +149 -44
- package/dist/languages/python.js.map +1 -1
- package/dist/languages/ruby.d.ts +115 -0
- package/dist/languages/ruby.d.ts.map +1 -0
- package/dist/languages/ruby.js +665 -0
- package/dist/languages/ruby.js.map +1 -0
- package/dist/languages/rust.d.ts.map +1 -1
- package/dist/languages/rust.js +103 -16
- package/dist/languages/rust.js.map +1 -1
- package/dist/languages/types.d.ts +228 -5
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/typescript.d.ts.map +1 -1
- package/dist/languages/typescript.js +201 -14
- package/dist/languages/typescript.js.map +1 -1
- package/dist/scoring/dimensions/documentation.d.ts +53 -0
- package/dist/scoring/dimensions/documentation.d.ts.map +1 -0
- package/dist/scoring/dimensions/documentation.js +106 -0
- package/dist/scoring/dimensions/documentation.js.map +1 -0
- package/dist/scoring/dimensions/dx.d.ts +53 -0
- package/dist/scoring/dimensions/dx.d.ts.map +1 -0
- package/dist/scoring/dimensions/dx.js +105 -0
- package/dist/scoring/dimensions/dx.js.map +1 -0
- package/dist/scoring/dimensions/maintainability.d.ts +53 -0
- package/dist/scoring/dimensions/maintainability.d.ts.map +1 -0
- package/dist/scoring/dimensions/maintainability.js +101 -0
- package/dist/scoring/dimensions/maintainability.js.map +1 -0
- package/dist/scoring/dimensions/quality.d.ts +108 -0
- package/dist/scoring/dimensions/quality.d.ts.map +1 -0
- package/dist/scoring/dimensions/quality.js +174 -0
- package/dist/scoring/dimensions/quality.js.map +1 -0
- package/dist/scoring/dimensions/security.d.ts +84 -0
- package/dist/scoring/dimensions/security.d.ts.map +1 -0
- package/dist/scoring/dimensions/security.js +135 -0
- package/dist/scoring/dimensions/security.js.map +1 -0
- package/dist/scoring/dimensions/testing.d.ts +56 -0
- package/dist/scoring/dimensions/testing.d.ts.map +1 -0
- package/dist/scoring/dimensions/testing.js +98 -0
- package/dist/scoring/dimensions/testing.js.map +1 -0
- package/dist/scoring/evaluator.d.ts +27 -0
- package/dist/scoring/evaluator.d.ts.map +1 -0
- package/dist/scoring/evaluator.js +124 -0
- package/dist/scoring/evaluator.js.map +1 -0
- package/dist/scoring/format.d.ts +34 -0
- package/dist/scoring/format.d.ts.map +1 -0
- package/dist/scoring/format.js +63 -0
- package/dist/scoring/format.js.map +1 -0
- package/dist/scoring/index.d.ts +37 -0
- package/dist/scoring/index.d.ts.map +1 -0
- package/dist/scoring/index.js +57 -0
- package/dist/scoring/index.js.map +1 -0
- package/dist/scoring/overall.d.ts +54 -0
- package/dist/scoring/overall.d.ts.map +1 -0
- package/dist/scoring/overall.js +76 -0
- package/dist/scoring/overall.js.map +1 -0
- package/dist/scoring/result.d.ts +111 -0
- package/dist/scoring/result.d.ts.map +1 -0
- package/dist/scoring/result.js +14 -0
- package/dist/scoring/result.js.map +1 -0
- package/dist/scoring/spec.d.ts +76 -0
- package/dist/scoring/spec.d.ts.map +1 -0
- package/dist/scoring/spec.js +22 -0
- package/dist/scoring/spec.js.map +1 -0
- package/dist/scoring/thresholds.d.ts +56 -0
- package/dist/scoring/thresholds.d.ts.map +1 -0
- package/dist/scoring/thresholds.js +75 -0
- package/dist/scoring/thresholds.js.map +1 -0
- package/dist/tools-cli.d.ts.map +1 -1
- package/dist/tools-cli.js +21 -2
- package/dist/tools-cli.js.map +1 -1
- package/dist/types.d.ts +17 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/templates/.claude/commands/dashboard.md +17 -9
- package/templates/.claude/rules/ruby.md +11 -0
- package/templates/configs/ruby/README.md +6 -0
- package/dist/analyzers/scoring.d.ts +0 -49
- package/dist/analyzers/scoring.d.ts.map +0 -1
- package/dist/analyzers/scoring.js +0 -422
- package/dist/analyzers/scoring.js.map +0 -1
- package/dist/analyzers/security/scoring.d.ts +0 -29
- package/dist/analyzers/security/scoring.d.ts.map +0 -1
- package/dist/analyzers/security/scoring.js +0 -40
- package/dist/analyzers/security/scoring.js.map +0 -1
- package/dist/analyzers/tools/osv-scanner-maven.d.ts +0 -42
- package/dist/analyzers/tools/osv-scanner-maven.d.ts.map +0 -1
- package/dist/analyzers/tools/osv-scanner-maven.js.map +0 -1
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical security aggregator (G_v4_8 / 2.4.7 Phase C1).
|
|
3
|
+
*
|
|
4
|
+
* One source of truth for "code findings by severity", "dependency
|
|
5
|
+
* advisories by severity", "unique advisory count", and cross-tool
|
|
6
|
+
* dedup. Every consumer (standalone vuln-scan, health-side scorer,
|
|
7
|
+
* BoM, dashboard) reads from `SecurityAggregate` instead of
|
|
8
|
+
* re-counting raw envelope arrays.
|
|
9
|
+
*
|
|
10
|
+
* The disease this closes (D086 / D087 / D091):
|
|
11
|
+
*
|
|
12
|
+
* - **D086** Health Security section and standalone vuln-scan Code
|
|
13
|
+
* Findings table both reported "code findings by severity" but
|
|
14
|
+
* came up with different numbers (`0C 11H 18M 0L` vs
|
|
15
|
+
* `0C 17H 14M 0L`) on the same repo. Two consumers, two
|
|
16
|
+
* aggregation paths, slightly-different inclusion rules.
|
|
17
|
+
*
|
|
18
|
+
* - **D087** Vuln-scan exec summary said "Subtotal: 70" (sum of
|
|
19
|
+
* dep-vuln severity buckets) and the same page later said
|
|
20
|
+
* "81 advisories" (findings.length). 70 vs 81 on one page.
|
|
21
|
+
*
|
|
22
|
+
* - **D091** A single TLS-bypass root finding surfaced twice in the
|
|
23
|
+
* Code Findings table (registry-grep at `:74` HIGH, semgrep at
|
|
24
|
+
* `:72` MEDIUM) because code findings carried no fingerprint and
|
|
25
|
+
* no cross-tool dedup ran.
|
|
26
|
+
*
|
|
27
|
+
* Architectural posture:
|
|
28
|
+
*
|
|
29
|
+
* - The aggregator sits BETWEEN gather and reports. Gather still
|
|
30
|
+
* produces raw envelopes (`gatherSecrets`, `gatherFileFindings`,
|
|
31
|
+
* `gatherCodePatterns`, `gatherTlsBypassFindings`, `gatherDepVulns`);
|
|
32
|
+
* the aggregator merges + dedups + buckets them into the canonical
|
|
33
|
+
* shape; consumers read by field name.
|
|
34
|
+
*
|
|
35
|
+
* - Three separately-named severity buckets (`codeBySeverity`,
|
|
36
|
+
* `depBySeverity`, `secretsBySeverity`) — the shape forbids any
|
|
37
|
+
* consumer from accidentally summing cross-axis again.
|
|
38
|
+
*
|
|
39
|
+
* - Two named dep counts (`dependencyAdvisoryUniqueCount` for the
|
|
40
|
+
* canonical user-facing total; `dependencyFindingsRawCount` for
|
|
41
|
+
* diagnostic audit). Renderers cannot pick "the wrong number"
|
|
42
|
+
* without naming which they want.
|
|
43
|
+
*
|
|
44
|
+
* - Code findings get a canonical-rule + line-window fingerprint;
|
|
45
|
+
* cross-tool collisions collapse to ONE CodeFinding with
|
|
46
|
+
* `keptSeverity = max(severities)` and `producedBy` listing all
|
|
47
|
+
* contributing tools. The `dedupCollisions` audit trail records
|
|
48
|
+
* every collapse for `--detailed` visibility.
|
|
49
|
+
*
|
|
50
|
+
* - `provenance` distinguishes "tool ran, 0 findings" from "tool
|
|
51
|
+
* didn't run" — drives D080-style "(not run: typescript)" labels.
|
|
52
|
+
*
|
|
53
|
+
* G_v4_8 architectural gate (`scripts/check-architecture.sh`) blocks
|
|
54
|
+
* `countBySeverity` / severity-Record accumulator declarations
|
|
55
|
+
* outside this file, mirroring G_v4_7's walker allowlist.
|
|
56
|
+
*/
|
|
57
|
+
import type { DepVulnFinding } from '../../languages/capabilities/types';
|
|
58
|
+
import type { Severity, SecurityFinding } from './types';
|
|
59
|
+
export type { Severity, FindingCategory, SecurityFinding } from './types';
|
|
60
|
+
/**
|
|
61
|
+
* Per-severity counts. Local copy (avoids cross-module import friction
|
|
62
|
+
* with `capabilities/types.SeverityCounts` — same shape, different
|
|
63
|
+
* module home).
|
|
64
|
+
*/
|
|
65
|
+
export interface SeverityCounts {
|
|
66
|
+
critical: number;
|
|
67
|
+
high: number;
|
|
68
|
+
medium: number;
|
|
69
|
+
low: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Post-aggregation code/secret/config finding. Extends raw
|
|
73
|
+
* `SecurityFinding` with the identity + provenance fields the
|
|
74
|
+
* aggregator stamps:
|
|
75
|
+
*
|
|
76
|
+
* - `fingerprint` — stable 16-char hash of
|
|
77
|
+
* `(canonicalRule | file | lineWindow)`. Same key across runs;
|
|
78
|
+
* enables diff tooling and dedup-by-identity downstream.
|
|
79
|
+
* - `canonicalRule` — normalized rule id from the canonical-rule
|
|
80
|
+
* registry. Different raw tool/rule pairs that describe the same
|
|
81
|
+
* root finding collapse to the same `canonicalRule`. Unmapped
|
|
82
|
+
* pairs pass through as `raw:${tool}:${rule}` — conservative
|
|
83
|
+
* default; new collapse rules require explicit registry entries.
|
|
84
|
+
* - `producedBy` — every raw `tool` that contributed to this
|
|
85
|
+
* finding. Length > 1 means cross-tool dedup fired.
|
|
86
|
+
*/
|
|
87
|
+
export interface CodeFinding extends SecurityFinding {
|
|
88
|
+
fingerprint: string;
|
|
89
|
+
canonicalRule: string;
|
|
90
|
+
producedBy: string[];
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* One collapsed-collision audit entry. Renders in `--detailed` so a
|
|
94
|
+
* security reviewer can verify "yes, these two tools agreed on this
|
|
95
|
+
* one finding" rather than wondering why a tool's findings count
|
|
96
|
+
* differs from the report's surface count.
|
|
97
|
+
*/
|
|
98
|
+
export interface DedupCollision {
|
|
99
|
+
canonicalRule: string;
|
|
100
|
+
file: string;
|
|
101
|
+
line: number;
|
|
102
|
+
keptSeverity: Severity;
|
|
103
|
+
collapsedFrom: ReadonlyArray<{
|
|
104
|
+
tool: string;
|
|
105
|
+
rule: string;
|
|
106
|
+
line: number;
|
|
107
|
+
severity: Severity;
|
|
108
|
+
}>;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Per-tool run-state provenance. Distinguishes "tool ran with zero
|
|
112
|
+
* findings" from "tool didn't run." Drives the "(not run: …)" labels
|
|
113
|
+
* on report tool-attribution lines and the security scorer's "scan
|
|
114
|
+
* was partial" cap signal (D025e / D080 lineage).
|
|
115
|
+
*/
|
|
116
|
+
export interface AggregateProvenance {
|
|
117
|
+
secrets: {
|
|
118
|
+
tool: string | null;
|
|
119
|
+
ran: boolean;
|
|
120
|
+
};
|
|
121
|
+
codePatterns: {
|
|
122
|
+
tool: string | null;
|
|
123
|
+
ran: boolean;
|
|
124
|
+
};
|
|
125
|
+
tlsBypass: {
|
|
126
|
+
ran: boolean;
|
|
127
|
+
patternCount: number;
|
|
128
|
+
};
|
|
129
|
+
fileFindings: {
|
|
130
|
+
ran: boolean;
|
|
131
|
+
};
|
|
132
|
+
depVulns: {
|
|
133
|
+
tool: string | null;
|
|
134
|
+
available: boolean;
|
|
135
|
+
unavailableReason: string;
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The canonical security aggregate. Every consumer reads from this;
|
|
140
|
+
* consumers MUST NOT re-aggregate from raw envelope arrays. The
|
|
141
|
+
* G_v4_8 architectural gate enforces this at commit time.
|
|
142
|
+
*/
|
|
143
|
+
export interface SecurityAggregate {
|
|
144
|
+
/** Code-pattern findings by severity (semgrep + tls-bypass-registry
|
|
145
|
+
* + any future per-pack code-pattern producers), post-dedup. */
|
|
146
|
+
codeBySeverity: SeverityCounts;
|
|
147
|
+
/** Dependency advisories by severity, derived from the
|
|
148
|
+
* fingerprint-unique advisory set (NOT the per-pack envelope
|
|
149
|
+
* count sum). Sums to `dependencyAdvisoryUniqueCount`. */
|
|
150
|
+
depBySeverity: SeverityCounts;
|
|
151
|
+
/** Secret + secret-adjacent findings (gitleaks + private-key files +
|
|
152
|
+
* .env-in-git) by severity. Each axis stays separate so consumers
|
|
153
|
+
* pick which they own. */
|
|
154
|
+
secretsBySeverity: SeverityCounts;
|
|
155
|
+
/** Findings partitioned by category, post-dedup. Renderers iterate
|
|
156
|
+
* these — never iterate raw envelope arrays. `dependency` is the
|
|
157
|
+
* fingerprint-unique advisory set. */
|
|
158
|
+
findingsByCategory: {
|
|
159
|
+
secret: ReadonlyArray<CodeFinding>;
|
|
160
|
+
code: ReadonlyArray<CodeFinding>;
|
|
161
|
+
config: ReadonlyArray<CodeFinding>;
|
|
162
|
+
dependency: ReadonlyArray<DepVulnFinding>;
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* The canonical user-facing advisory count: unique fingerprints
|
|
166
|
+
* across every pack's findings. Use for the vuln-scan "Subtotal:"
|
|
167
|
+
* line, BoM `totalAdvisories`, and the "Showing N of M" denominator.
|
|
168
|
+
* Aligns with BoM's existing fingerprint-unique semantics (D076 /
|
|
169
|
+
* D085) so vuln-scan and BoM never report different totals.
|
|
170
|
+
*/
|
|
171
|
+
dependencyAdvisoryUniqueCount: number;
|
|
172
|
+
/**
|
|
173
|
+
* Diagnostic-only: per-pack envelope.findings.length sum BEFORE
|
|
174
|
+
* fingerprint dedup. Surfaces in `--detailed` audit logs so the
|
|
175
|
+
* delta vs `dependencyAdvisoryUniqueCount` is visible. Renderers
|
|
176
|
+
* should NOT use this for any user-facing count.
|
|
177
|
+
*/
|
|
178
|
+
dependencyFindingsRawCount: number;
|
|
179
|
+
/** Audit trail of every cross-tool / cross-line-window collapse.
|
|
180
|
+
* Empty in the no-collision case. */
|
|
181
|
+
dedupCollisions: ReadonlyArray<DedupCollision>;
|
|
182
|
+
/** Per-source provenance — drives "(not run: typescript)" labels. */
|
|
183
|
+
provenance: AggregateProvenance;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Input envelopes for `buildSecurityAggregate`. Each field maps 1:1
|
|
187
|
+
* to a `gather*` function in `security/gather.ts`. The aggregator
|
|
188
|
+
* never invokes I/O; it's a pure function over already-gathered
|
|
189
|
+
* data, which keeps unit testing trivial.
|
|
190
|
+
*/
|
|
191
|
+
export interface SecurityAggregateInput {
|
|
192
|
+
secrets: {
|
|
193
|
+
findings: SecurityFinding[];
|
|
194
|
+
toolUsed: string | null;
|
|
195
|
+
};
|
|
196
|
+
fileFindings: SecurityFinding[];
|
|
197
|
+
codePatterns: {
|
|
198
|
+
findings: SecurityFinding[];
|
|
199
|
+
toolUsed: string | null;
|
|
200
|
+
};
|
|
201
|
+
tlsBypass: SecurityFinding[];
|
|
202
|
+
/** Pattern count from `allTlsBypassPatterns()` — drives the
|
|
203
|
+
* `provenance.tlsBypass.ran` flag (ran=false when no patterns were
|
|
204
|
+
* registered, NOT when 0 findings matched against a non-empty
|
|
205
|
+
* pattern set). */
|
|
206
|
+
tlsBypassPatternCount: number;
|
|
207
|
+
depVulns: {
|
|
208
|
+
findings: DepVulnFinding[];
|
|
209
|
+
tool: string | null;
|
|
210
|
+
available: boolean;
|
|
211
|
+
unavailableReason: string;
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Build the canonical aggregate from per-gatherer envelopes. Pure
|
|
216
|
+
* function — same input always produces the same output.
|
|
217
|
+
*
|
|
218
|
+
* Dedup pipeline (code-side):
|
|
219
|
+
* 1. Concat raw findings from secrets/fileFindings/codePatterns/tlsBypass.
|
|
220
|
+
* 2. Group by `(canonicalRule, file, lineWindow)` key.
|
|
221
|
+
* 3. For each group:
|
|
222
|
+
* - Emit ONE `CodeFinding` with `keptSeverity = max(severities)`,
|
|
223
|
+
* `producedBy` = unique sources.
|
|
224
|
+
* - If the group had >1 raw finding, record a `DedupCollision`
|
|
225
|
+
* audit entry.
|
|
226
|
+
*
|
|
227
|
+
* Dedup pipeline (dep-side):
|
|
228
|
+
* - Group `depVulns.findings` by `fingerprint`.
|
|
229
|
+
* - For each group: pick the highest-severity entry as the
|
|
230
|
+
* representative; severity counts are derived from the unique
|
|
231
|
+
* set so they match `dependencyAdvisoryUniqueCount`.
|
|
232
|
+
* - Findings without a fingerprint pass through unchanged (defensive;
|
|
233
|
+
* `stampFingerprints` in `gatherDepVulns` runs before this).
|
|
234
|
+
*/
|
|
235
|
+
export declare function buildSecurityAggregate(input: SecurityAggregateInput): SecurityAggregate;
|
|
236
|
+
//# sourceMappingURL=aggregator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregator.d.ts","sourceRoot":"","sources":["../../../src/analyzers/security/aggregator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical security aggregator (G_v4_8 / 2.4.7 Phase C1).
|
|
4
|
+
*
|
|
5
|
+
* One source of truth for "code findings by severity", "dependency
|
|
6
|
+
* advisories by severity", "unique advisory count", and cross-tool
|
|
7
|
+
* dedup. Every consumer (standalone vuln-scan, health-side scorer,
|
|
8
|
+
* BoM, dashboard) reads from `SecurityAggregate` instead of
|
|
9
|
+
* re-counting raw envelope arrays.
|
|
10
|
+
*
|
|
11
|
+
* The disease this closes (D086 / D087 / D091):
|
|
12
|
+
*
|
|
13
|
+
* - **D086** Health Security section and standalone vuln-scan Code
|
|
14
|
+
* Findings table both reported "code findings by severity" but
|
|
15
|
+
* came up with different numbers (`0C 11H 18M 0L` vs
|
|
16
|
+
* `0C 17H 14M 0L`) on the same repo. Two consumers, two
|
|
17
|
+
* aggregation paths, slightly-different inclusion rules.
|
|
18
|
+
*
|
|
19
|
+
* - **D087** Vuln-scan exec summary said "Subtotal: 70" (sum of
|
|
20
|
+
* dep-vuln severity buckets) and the same page later said
|
|
21
|
+
* "81 advisories" (findings.length). 70 vs 81 on one page.
|
|
22
|
+
*
|
|
23
|
+
* - **D091** A single TLS-bypass root finding surfaced twice in the
|
|
24
|
+
* Code Findings table (registry-grep at `:74` HIGH, semgrep at
|
|
25
|
+
* `:72` MEDIUM) because code findings carried no fingerprint and
|
|
26
|
+
* no cross-tool dedup ran.
|
|
27
|
+
*
|
|
28
|
+
* Architectural posture:
|
|
29
|
+
*
|
|
30
|
+
* - The aggregator sits BETWEEN gather and reports. Gather still
|
|
31
|
+
* produces raw envelopes (`gatherSecrets`, `gatherFileFindings`,
|
|
32
|
+
* `gatherCodePatterns`, `gatherTlsBypassFindings`, `gatherDepVulns`);
|
|
33
|
+
* the aggregator merges + dedups + buckets them into the canonical
|
|
34
|
+
* shape; consumers read by field name.
|
|
35
|
+
*
|
|
36
|
+
* - Three separately-named severity buckets (`codeBySeverity`,
|
|
37
|
+
* `depBySeverity`, `secretsBySeverity`) — the shape forbids any
|
|
38
|
+
* consumer from accidentally summing cross-axis again.
|
|
39
|
+
*
|
|
40
|
+
* - Two named dep counts (`dependencyAdvisoryUniqueCount` for the
|
|
41
|
+
* canonical user-facing total; `dependencyFindingsRawCount` for
|
|
42
|
+
* diagnostic audit). Renderers cannot pick "the wrong number"
|
|
43
|
+
* without naming which they want.
|
|
44
|
+
*
|
|
45
|
+
* - Code findings get a canonical-rule + line-window fingerprint;
|
|
46
|
+
* cross-tool collisions collapse to ONE CodeFinding with
|
|
47
|
+
* `keptSeverity = max(severities)` and `producedBy` listing all
|
|
48
|
+
* contributing tools. The `dedupCollisions` audit trail records
|
|
49
|
+
* every collapse for `--detailed` visibility.
|
|
50
|
+
*
|
|
51
|
+
* - `provenance` distinguishes "tool ran, 0 findings" from "tool
|
|
52
|
+
* didn't run" — drives D080-style "(not run: typescript)" labels.
|
|
53
|
+
*
|
|
54
|
+
* G_v4_8 architectural gate (`scripts/check-architecture.sh`) blocks
|
|
55
|
+
* `countBySeverity` / severity-Record accumulator declarations
|
|
56
|
+
* outside this file, mirroring G_v4_7's walker allowlist.
|
|
57
|
+
*/
|
|
58
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
59
|
+
exports.buildSecurityAggregate = buildSecurityAggregate;
|
|
60
|
+
const crypto_1 = require("crypto");
|
|
61
|
+
// ─── Canonical-rule registry ──────────────────────────────────────────────
|
|
62
|
+
/**
|
|
63
|
+
* Maps raw `(tool, rule)` pairs to a canonical rule id. Two raw
|
|
64
|
+
* findings with the same canonical rule (and same file + line window)
|
|
65
|
+
* collapse to one `CodeFinding` with `keptSeverity = max` and
|
|
66
|
+
* `producedBy = [tool₁, tool₂, …]`.
|
|
67
|
+
*
|
|
68
|
+
* Unmapped pairs fall through to `raw:${tool}:${rule}` — never
|
|
69
|
+
* accidentally collapses unrelated findings. Adding a new collapse
|
|
70
|
+
* is a one-line addition here; no aggregator code changes.
|
|
71
|
+
*
|
|
72
|
+
* Initial entries close D091's observed TLS-bypass cross-tool
|
|
73
|
+
* double-counting. Future entries land when a new language pack or
|
|
74
|
+
* semgrep ruleset surfaces overlap with an existing finding type.
|
|
75
|
+
*/
|
|
76
|
+
const CANONICAL_RULE_MAP = new Map([
|
|
77
|
+
// TLS / certificate validation bypass — D091 closure
|
|
78
|
+
['tls-bypass-registry:tls-validation-disabled', 'canonical:tls-bypass'],
|
|
79
|
+
['semgrep:bypass-tls-verification', 'canonical:tls-bypass'],
|
|
80
|
+
['semgrep:nodejsscan.node_tls_reject_unauthorized', 'canonical:tls-bypass'],
|
|
81
|
+
// Private-key file on disk — find + gitleaks may both surface
|
|
82
|
+
['find:private-key-file', 'canonical:private-key-on-disk'],
|
|
83
|
+
['gitleaks:private-key', 'canonical:private-key-on-disk'],
|
|
84
|
+
]);
|
|
85
|
+
function canonicalRuleFor(tool, rule) {
|
|
86
|
+
return CANONICAL_RULE_MAP.get(`${tool}:${rule}`) ?? `raw:${tool}:${rule}`;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Line-window bucketing. Tools report the same code construct at
|
|
90
|
+
* slightly-different lines (semgrep on the declaration, registry-grep
|
|
91
|
+
* on the assignment — D091's `:72` vs `:74` shape). 3-line buckets
|
|
92
|
+
* absorb that drift without collapsing genuinely-different findings
|
|
93
|
+
* in the same file.
|
|
94
|
+
*
|
|
95
|
+
* Boundary edge case closed by C1.10: the natural fixed-boundary
|
|
96
|
+
* bucketing alone would miss adjacent findings straddling a
|
|
97
|
+
* multiple-of-3 (web-client surfaced DBConfigureForm.js:43 + :45 →
|
|
98
|
+
* buckets 42 + 45 → no collapse pre-C1.10). The grouping loop now
|
|
99
|
+
* does a neighbor-bucket lookup (naturalBucket ± 3) after the natural
|
|
100
|
+
* miss, restoring D091's intent across boundary-straddling pairs.
|
|
101
|
+
* Effective collapse window: ~3-5 lines depending on alignment.
|
|
102
|
+
*/
|
|
103
|
+
function lineWindowFor(line) {
|
|
104
|
+
return Math.floor(line / 3) * 3;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Stable 16-char hex hash of `(canonicalRule | file | lineWindow)`.
|
|
108
|
+
* NUL-separated so distinct tuples can't collide via concatenation
|
|
109
|
+
* tricks. Mirrors `tools/fingerprint.computeFingerprint`'s format
|
|
110
|
+
* (SHA-1 first 8 bytes hex) so dep-vuln and code-finding fingerprints
|
|
111
|
+
* share a downstream type contract.
|
|
112
|
+
*/
|
|
113
|
+
function computeCodeFingerprint(canonicalRule, file, line) {
|
|
114
|
+
const input = `${canonicalRule}\0${file}\0${lineWindowFor(line)}`;
|
|
115
|
+
return (0, crypto_1.createHash)('sha1').update(input).digest('hex').slice(0, 16);
|
|
116
|
+
}
|
|
117
|
+
// ─── Severity helpers ─────────────────────────────────────────────────────
|
|
118
|
+
const SEVERITY_RANK = {
|
|
119
|
+
critical: 3,
|
|
120
|
+
high: 2,
|
|
121
|
+
medium: 1,
|
|
122
|
+
low: 0,
|
|
123
|
+
};
|
|
124
|
+
function maxSeverity(a, b) {
|
|
125
|
+
return SEVERITY_RANK[a] >= SEVERITY_RANK[b] ? a : b;
|
|
126
|
+
}
|
|
127
|
+
function emptyCounts() {
|
|
128
|
+
return { critical: 0, high: 0, medium: 0, low: 0 };
|
|
129
|
+
}
|
|
130
|
+
function bumpCounts(counts, severity) {
|
|
131
|
+
counts[severity]++;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Build the canonical aggregate from per-gatherer envelopes. Pure
|
|
135
|
+
* function — same input always produces the same output.
|
|
136
|
+
*
|
|
137
|
+
* Dedup pipeline (code-side):
|
|
138
|
+
* 1. Concat raw findings from secrets/fileFindings/codePatterns/tlsBypass.
|
|
139
|
+
* 2. Group by `(canonicalRule, file, lineWindow)` key.
|
|
140
|
+
* 3. For each group:
|
|
141
|
+
* - Emit ONE `CodeFinding` with `keptSeverity = max(severities)`,
|
|
142
|
+
* `producedBy` = unique sources.
|
|
143
|
+
* - If the group had >1 raw finding, record a `DedupCollision`
|
|
144
|
+
* audit entry.
|
|
145
|
+
*
|
|
146
|
+
* Dedup pipeline (dep-side):
|
|
147
|
+
* - Group `depVulns.findings` by `fingerprint`.
|
|
148
|
+
* - For each group: pick the highest-severity entry as the
|
|
149
|
+
* representative; severity counts are derived from the unique
|
|
150
|
+
* set so they match `dependencyAdvisoryUniqueCount`.
|
|
151
|
+
* - Findings without a fingerprint pass through unchanged (defensive;
|
|
152
|
+
* `stampFingerprints` in `gatherDepVulns` runs before this).
|
|
153
|
+
*/
|
|
154
|
+
function buildSecurityAggregate(input) {
|
|
155
|
+
// ─── Code-side dedup ────────────────────────────────────────────────
|
|
156
|
+
const rawCodeFindings = [
|
|
157
|
+
...input.secrets.findings,
|
|
158
|
+
...input.fileFindings,
|
|
159
|
+
...input.codePatterns.findings,
|
|
160
|
+
...input.tlsBypass,
|
|
161
|
+
];
|
|
162
|
+
const groups = new Map();
|
|
163
|
+
for (const f of rawCodeFindings) {
|
|
164
|
+
const canonicalRule = canonicalRuleFor(f.tool, f.rule);
|
|
165
|
+
const naturalFingerprint = computeCodeFingerprint(canonicalRule, f.file, f.line);
|
|
166
|
+
// C1.10: neighbor-bucket lookup. The 3-line fixed bucket misses
|
|
167
|
+
// adjacent findings that straddle a multiple-of-3 line (web-client
|
|
168
|
+
// DBConfigureForm.js:43 + :45 → buckets 42 + 45 → different keys
|
|
169
|
+
// → no collapse pre-C1.10). Look up the natural bucket first, then
|
|
170
|
+
// the adjacent buckets (naturalBucket ± 3 via `line ± 3`). Same
|
|
171
|
+
// canonical-rule + file + neighbor-bucket counts as a match; merges
|
|
172
|
+
// into that group. Effective dedup window grows from "0-2 lines
|
|
173
|
+
// within one bucket" to "3-5 lines across one bucket boundary."
|
|
174
|
+
let fingerprint = naturalFingerprint;
|
|
175
|
+
let existing = groups.get(fingerprint);
|
|
176
|
+
if (!existing) {
|
|
177
|
+
for (const offset of [-3, 3]) {
|
|
178
|
+
const neighborFingerprint = computeCodeFingerprint(canonicalRule, f.file, f.line + offset);
|
|
179
|
+
const candidate = groups.get(neighborFingerprint);
|
|
180
|
+
if (candidate) {
|
|
181
|
+
existing = candidate;
|
|
182
|
+
fingerprint = neighborFingerprint;
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (existing) {
|
|
188
|
+
existing.severity = maxSeverity(existing.severity, f.severity);
|
|
189
|
+
existing.producedBy.add(f.tool);
|
|
190
|
+
existing.raws.push({
|
|
191
|
+
tool: f.tool,
|
|
192
|
+
rule: f.rule,
|
|
193
|
+
line: f.line,
|
|
194
|
+
severity: f.severity,
|
|
195
|
+
});
|
|
196
|
+
// Prefer the lower line number as the canonical line — semgrep
|
|
197
|
+
// typically reports the declaration (earlier line) while
|
|
198
|
+
// registry-grep reports the assignment; the declaration is the
|
|
199
|
+
// more useful navigation target. Tie-break by category preserve.
|
|
200
|
+
if (f.line < existing.line) {
|
|
201
|
+
existing.line = f.line;
|
|
202
|
+
existing.title = f.title;
|
|
203
|
+
existing.rule = f.rule;
|
|
204
|
+
existing.tool = f.tool;
|
|
205
|
+
existing.cwe = f.cwe || existing.cwe;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
groups.set(fingerprint, {
|
|
210
|
+
fingerprint,
|
|
211
|
+
canonicalRule,
|
|
212
|
+
file: f.file,
|
|
213
|
+
line: f.line,
|
|
214
|
+
severity: f.severity,
|
|
215
|
+
category: f.category,
|
|
216
|
+
cwe: f.cwe,
|
|
217
|
+
rule: f.rule,
|
|
218
|
+
title: f.title,
|
|
219
|
+
tool: f.tool,
|
|
220
|
+
producedBy: new Set([f.tool]),
|
|
221
|
+
raws: [
|
|
222
|
+
{
|
|
223
|
+
tool: f.tool,
|
|
224
|
+
rule: f.rule,
|
|
225
|
+
line: f.line,
|
|
226
|
+
severity: f.severity,
|
|
227
|
+
},
|
|
228
|
+
],
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const codeFindingsByCategory = {
|
|
233
|
+
secret: [],
|
|
234
|
+
code: [],
|
|
235
|
+
config: [],
|
|
236
|
+
};
|
|
237
|
+
const codeBySeverity = emptyCounts();
|
|
238
|
+
const secretsBySeverity = emptyCounts();
|
|
239
|
+
const dedupCollisions = [];
|
|
240
|
+
for (const g of groups.values()) {
|
|
241
|
+
const finding = {
|
|
242
|
+
severity: g.severity,
|
|
243
|
+
category: g.category,
|
|
244
|
+
cwe: g.cwe,
|
|
245
|
+
rule: g.rule,
|
|
246
|
+
title: g.title,
|
|
247
|
+
file: g.file,
|
|
248
|
+
line: g.line,
|
|
249
|
+
tool: g.tool,
|
|
250
|
+
fingerprint: g.fingerprint,
|
|
251
|
+
canonicalRule: g.canonicalRule,
|
|
252
|
+
producedBy: [...g.producedBy].sort(),
|
|
253
|
+
};
|
|
254
|
+
if (g.category === 'secret') {
|
|
255
|
+
codeFindingsByCategory.secret.push(finding);
|
|
256
|
+
bumpCounts(secretsBySeverity, g.severity);
|
|
257
|
+
}
|
|
258
|
+
else if (g.category === 'config') {
|
|
259
|
+
codeFindingsByCategory.config.push(finding);
|
|
260
|
+
// Config findings (`.env in git`) are secret-adjacent — they
|
|
261
|
+
// share the secrets axis so the Security dimension treats them
|
|
262
|
+
// as the same risk class. Pre-aggregator code paths agreed on
|
|
263
|
+
// this; we preserve it.
|
|
264
|
+
bumpCounts(secretsBySeverity, g.severity);
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
codeFindingsByCategory.code.push(finding);
|
|
268
|
+
bumpCounts(codeBySeverity, g.severity);
|
|
269
|
+
}
|
|
270
|
+
if (g.raws.length > 1) {
|
|
271
|
+
dedupCollisions.push({
|
|
272
|
+
canonicalRule: g.canonicalRule,
|
|
273
|
+
file: g.file,
|
|
274
|
+
line: g.line,
|
|
275
|
+
keptSeverity: g.severity,
|
|
276
|
+
collapsedFrom: g.raws,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// ─── Dep-side dedup ─────────────────────────────────────────────────
|
|
281
|
+
// Group by fingerprint. Findings without a fingerprint (defensive
|
|
282
|
+
// path — shouldn't happen post-`stampFingerprints`) get a synthetic
|
|
283
|
+
// unique key so they pass through individually.
|
|
284
|
+
const depGroups = new Map();
|
|
285
|
+
let syntheticFingerprintCounter = 0;
|
|
286
|
+
for (const f of input.depVulns.findings) {
|
|
287
|
+
const key = f.fingerprint ?? `__unstamped__${syntheticFingerprintCounter++}`;
|
|
288
|
+
const existing = depGroups.get(key);
|
|
289
|
+
if (!existing) {
|
|
290
|
+
depGroups.set(key, f);
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
// Keep the higher-severity representative. Same advisory may
|
|
294
|
+
// appear multiple times if cross-pack joins didn't already
|
|
295
|
+
// collapse it (defensive).
|
|
296
|
+
if (SEVERITY_RANK[f.severity] > SEVERITY_RANK[existing.severity]) {
|
|
297
|
+
depGroups.set(key, f);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
const uniqueDepFindings = [...depGroups.values()];
|
|
302
|
+
const depBySeverity = emptyCounts();
|
|
303
|
+
for (const f of uniqueDepFindings) {
|
|
304
|
+
bumpCounts(depBySeverity, f.severity);
|
|
305
|
+
}
|
|
306
|
+
// ─── Provenance ─────────────────────────────────────────────────────
|
|
307
|
+
const provenance = {
|
|
308
|
+
secrets: {
|
|
309
|
+
tool: input.secrets.toolUsed,
|
|
310
|
+
ran: input.secrets.toolUsed !== null,
|
|
311
|
+
},
|
|
312
|
+
codePatterns: {
|
|
313
|
+
tool: input.codePatterns.toolUsed,
|
|
314
|
+
ran: input.codePatterns.toolUsed !== null,
|
|
315
|
+
},
|
|
316
|
+
tlsBypass: {
|
|
317
|
+
// ran=true means the registry walk happened (patterns existed).
|
|
318
|
+
// ran=false means no pack registered TLS-bypass patterns — a
|
|
319
|
+
// legitimate "nothing to scan" state on a repo with no active
|
|
320
|
+
// packs declaring patterns.
|
|
321
|
+
ran: input.tlsBypassPatternCount > 0,
|
|
322
|
+
patternCount: input.tlsBypassPatternCount,
|
|
323
|
+
},
|
|
324
|
+
fileFindings: { ran: true },
|
|
325
|
+
depVulns: {
|
|
326
|
+
tool: input.depVulns.tool,
|
|
327
|
+
available: input.depVulns.available,
|
|
328
|
+
unavailableReason: input.depVulns.unavailableReason,
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
return {
|
|
332
|
+
codeBySeverity,
|
|
333
|
+
depBySeverity,
|
|
334
|
+
secretsBySeverity,
|
|
335
|
+
findingsByCategory: {
|
|
336
|
+
secret: codeFindingsByCategory.secret,
|
|
337
|
+
code: codeFindingsByCategory.code,
|
|
338
|
+
config: codeFindingsByCategory.config,
|
|
339
|
+
dependency: uniqueDepFindings,
|
|
340
|
+
},
|
|
341
|
+
dependencyAdvisoryUniqueCount: uniqueDepFindings.length,
|
|
342
|
+
dependencyFindingsRawCount: input.depVulns.findings.length,
|
|
343
|
+
dedupCollisions,
|
|
344
|
+
provenance,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=aggregator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregator.js","sourceRoot":"","sources":["../../../src/analyzers/security/aggregator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { SecurityReport } from './types';
|
|
2
2
|
import { RankedAction } from '../remediation';
|
|
3
|
-
import {
|
|
3
|
+
import { SecurityScoreInput } from '../../scoring';
|
|
4
4
|
export interface SecurityDetailedReport extends SecurityReport {
|
|
5
5
|
schemaVersion: string;
|
|
6
6
|
securityScore: number;
|
|
7
|
-
actions: Array<RankedAction<
|
|
7
|
+
actions: Array<RankedAction<SecurityScoreInput>>;
|
|
8
8
|
}
|
|
9
9
|
export declare function buildSecurityDetailed(report: SecurityReport): SecurityDetailedReport;
|
|
10
10
|
export declare function formatSecurityDetailedMarkdown(detailed: SecurityDetailedReport, elapsed: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detailed.d.ts","sourceRoot":"","sources":["../../../src/analyzers/security/detailed.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAA6B,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,YAAY,EAAQ,MAAM,gBAAgB,CAAC;AAEpD,OAAO,
|
|
1
|
+
{"version":3,"file":"detailed.d.ts","sourceRoot":"","sources":["../../../src/analyzers/security/detailed.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAA6B,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,YAAY,EAAQ,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EAAyB,kBAAkB,EAAgB,MAAM,eAAe,CAAC;AAGxF,MAAM,WAAW,sBAAuB,SAAQ,cAAc;IAC5D,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC,CAAC;CAClD;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,GAAG,sBAAsB,CAYpF;AAID,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,sBAAsB,EAChC,OAAO,EAAE,MAAM,GACd,MAAM,CAoKR"}
|
|
@@ -4,15 +4,18 @@ exports.buildSecurityDetailed = buildSecurityDetailed;
|
|
|
4
4
|
exports.formatSecurityDetailedMarkdown = formatSecurityDetailedMarkdown;
|
|
5
5
|
const remediation_1 = require("../remediation");
|
|
6
6
|
const actions_1 = require("./actions");
|
|
7
|
-
const scoring_1 = require("
|
|
7
|
+
const scoring_1 = require("../../scoring");
|
|
8
|
+
const tools_unavailable_prose_1 = require("../tools/tools-unavailable-prose");
|
|
8
9
|
function buildSecurityDetailed(report) {
|
|
9
|
-
const
|
|
10
|
-
const
|
|
10
|
+
const input = (0, actions_1.countsFromReport)(report);
|
|
11
|
+
const scoreFromInput = (i) => (0, scoring_1.evaluateSpec)(scoring_1.SECURITY_SCORING_SPEC, i);
|
|
12
|
+
const actions = (0, remediation_1.rank)((0, actions_1.buildSecurityActions)(report), input, scoreFromInput);
|
|
11
13
|
return {
|
|
12
14
|
...report,
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
// v13 carries the unified scorer output; same path the health
|
|
16
|
+
// audit's Security dimension uses, identical scores.
|
|
17
|
+
schemaVersion: '13',
|
|
18
|
+
securityScore: scoreFromInput(input).score,
|
|
16
19
|
actions,
|
|
17
20
|
};
|
|
18
21
|
}
|
|
@@ -157,9 +160,7 @@ function formatSecurityDetailedMarkdown(detailed, elapsed) {
|
|
|
157
160
|
L.push('');
|
|
158
161
|
}
|
|
159
162
|
L.push(`**Tools used:** ${detailed.toolsUsed.join(', ')}`);
|
|
160
|
-
|
|
161
|
-
L.push(`**Tools unavailable:** ${detailed.toolsUnavailable.join(', ')}`);
|
|
162
|
-
}
|
|
163
|
+
L.push(...(0, tools_unavailable_prose_1.renderToolsUnavailableLines)(detailed.toolsUnavailable));
|
|
163
164
|
L.push(`**Analysis time:** ${elapsed}s`);
|
|
164
165
|
L.push('');
|
|
165
166
|
L.push('*Generated by [VyuhLabs DXKit](https://www.npmjs.com/package/@vyuhlabs/dxkit) — detailed mode*');
|