@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,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security dimension — declarative scoring spec.
|
|
3
|
+
*
|
|
4
|
+
* Methodology: severity-dominant rating per ISO/IEC 5055 (automated
|
|
5
|
+
* source code quality measures, CISQ-driven) layered with CVSS v4
|
|
6
|
+
* (FIRST.org) for vulnerability severity bands. The spec encodes:
|
|
7
|
+
*
|
|
8
|
+
* - Penalty deductions for secrets, private keys, `.env` in git,
|
|
9
|
+
* code-pattern findings (semgrep et al), and dependency
|
|
10
|
+
* vulnerabilities. Each penalty surfaces as a discrete Deduction
|
|
11
|
+
* with a human-readable reason.
|
|
12
|
+
* - Cap rules that bound the rating when specific blocker classes
|
|
13
|
+
* are present (see `src/scoring/STANDARDS.md` for the cap
|
|
14
|
+
* taxonomy):
|
|
15
|
+
* trust-broken (40) — committed credentials
|
|
16
|
+
* uncertainty (65) — dep-vuln scanner did not run
|
|
17
|
+
* fixable-finding (79) — open HIGH/CRITICAL code finding
|
|
18
|
+
*
|
|
19
|
+
* The evaluator (`evaluateSpec`) consumes this spec + a
|
|
20
|
+
* `SecurityScoreInput` and produces the canonical `ScoreResult`. Both
|
|
21
|
+
* the health audit's Security dimension and the standalone
|
|
22
|
+
* vulnerability scan call the same path — same input ⇒ same number
|
|
23
|
+
* by construction.
|
|
24
|
+
*
|
|
25
|
+
* Adapters that build `SecurityScoreInput` from their domain data:
|
|
26
|
+
*
|
|
27
|
+
* - Health side: `src/analyzers/security/shallow.ts:toSecurityScoreInput`
|
|
28
|
+
* reads from `ScoreInput { metrics, capabilities }`. Falls back
|
|
29
|
+
* to grep-based HealthMetrics counts when `capabilities.codePatterns`
|
|
30
|
+
* is absent (semgrep unavailable).
|
|
31
|
+
* - Standalone side: `src/analyzers/security/actions.ts:countsFromReport`
|
|
32
|
+
* reads from `SecurityReport.findings` by partitioning on rule +
|
|
33
|
+
* category.
|
|
34
|
+
*
|
|
35
|
+
* Both adapters land on this same `SecurityScoreInput` shape; both
|
|
36
|
+
* dispatch through the same spec; both observe identical scores.
|
|
37
|
+
*/
|
|
38
|
+
import type { DimensionScoringSpec } from '../spec';
|
|
39
|
+
/** Severity counts shape, kept inline for clarity at call sites. */
|
|
40
|
+
interface SeverityCounts {
|
|
41
|
+
critical: number;
|
|
42
|
+
high: number;
|
|
43
|
+
medium: number;
|
|
44
|
+
low: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Clean partition of the security signal universe. Each finding the
|
|
48
|
+
* gather code emits maps to exactly one field — no double-counting,
|
|
49
|
+
* no missed contributions. Both health-side and standalone-side
|
|
50
|
+
* adapters produce this shape.
|
|
51
|
+
*/
|
|
52
|
+
export interface SecurityScoreInput {
|
|
53
|
+
/** Gitleaks-detected secrets (hardcoded credentials, API keys). */
|
|
54
|
+
secretFindings: number;
|
|
55
|
+
/** Private key / cert files on disk (*.key, *.pem). */
|
|
56
|
+
privateKeyFiles: number;
|
|
57
|
+
/** .env files tracked in git. */
|
|
58
|
+
envFilesInGit: number;
|
|
59
|
+
/**
|
|
60
|
+
* Semgrep code-pattern findings by severity. Includes eval/exec,
|
|
61
|
+
* TLS verification disabled, SQL injection, XSS, CORS, SSRF, and
|
|
62
|
+
* every other static-analysis pattern the active language packs'
|
|
63
|
+
* rulesets cover.
|
|
64
|
+
*/
|
|
65
|
+
codeFindings: SeverityCounts;
|
|
66
|
+
/** Dependency-vulnerability counts unioned across active packs. */
|
|
67
|
+
depVulns: SeverityCounts;
|
|
68
|
+
/**
|
|
69
|
+
* True if at least one active pack's depVulns gather reached
|
|
70
|
+
* success OR cleanly reported `no-manifest`; false if any pack
|
|
71
|
+
* returned `unavailable` (tool absent / no output / parse fail).
|
|
72
|
+
*
|
|
73
|
+
* When false, the `dep-vulns-unavailable` cap fires and bounds
|
|
74
|
+
* the score at the uncertainty tier ceiling regardless of other
|
|
75
|
+
* signals — dxkit can't honestly claim a top-tier score when it
|
|
76
|
+
* couldn't actually scan the deps.
|
|
77
|
+
*
|
|
78
|
+
* Adapters MUST populate this from `DepVulnSummary.available`.
|
|
79
|
+
*/
|
|
80
|
+
depVulnsAvailable: boolean;
|
|
81
|
+
}
|
|
82
|
+
export declare const SECURITY_SCORING_SPEC: DimensionScoringSpec<SecurityScoreInput>;
|
|
83
|
+
export {};
|
|
84
|
+
//# sourceMappingURL=security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../../src/scoring/dimensions/security.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD,oEAAoE;AACpE,UAAU,cAAc;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,cAAc,EAAE,MAAM,CAAC;IACvB,uDAAuD;IACvD,eAAe,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,YAAY,EAAE,cAAc,CAAC;IAC7B,mEAAmE;IACnE,QAAQ,EAAE,cAAc,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAUD,eAAO,MAAM,qBAAqB,EAAE,oBAAoB,CAAC,kBAAkB,CAoF1E,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Security dimension — declarative scoring spec.
|
|
4
|
+
*
|
|
5
|
+
* Methodology: severity-dominant rating per ISO/IEC 5055 (automated
|
|
6
|
+
* source code quality measures, CISQ-driven) layered with CVSS v4
|
|
7
|
+
* (FIRST.org) for vulnerability severity bands. The spec encodes:
|
|
8
|
+
*
|
|
9
|
+
* - Penalty deductions for secrets, private keys, `.env` in git,
|
|
10
|
+
* code-pattern findings (semgrep et al), and dependency
|
|
11
|
+
* vulnerabilities. Each penalty surfaces as a discrete Deduction
|
|
12
|
+
* with a human-readable reason.
|
|
13
|
+
* - Cap rules that bound the rating when specific blocker classes
|
|
14
|
+
* are present (see `src/scoring/STANDARDS.md` for the cap
|
|
15
|
+
* taxonomy):
|
|
16
|
+
* trust-broken (40) — committed credentials
|
|
17
|
+
* uncertainty (65) — dep-vuln scanner did not run
|
|
18
|
+
* fixable-finding (79) — open HIGH/CRITICAL code finding
|
|
19
|
+
*
|
|
20
|
+
* The evaluator (`evaluateSpec`) consumes this spec + a
|
|
21
|
+
* `SecurityScoreInput` and produces the canonical `ScoreResult`. Both
|
|
22
|
+
* the health audit's Security dimension and the standalone
|
|
23
|
+
* vulnerability scan call the same path — same input ⇒ same number
|
|
24
|
+
* by construction.
|
|
25
|
+
*
|
|
26
|
+
* Adapters that build `SecurityScoreInput` from their domain data:
|
|
27
|
+
*
|
|
28
|
+
* - Health side: `src/analyzers/security/shallow.ts:toSecurityScoreInput`
|
|
29
|
+
* reads from `ScoreInput { metrics, capabilities }`. Falls back
|
|
30
|
+
* to grep-based HealthMetrics counts when `capabilities.codePatterns`
|
|
31
|
+
* is absent (semgrep unavailable).
|
|
32
|
+
* - Standalone side: `src/analyzers/security/actions.ts:countsFromReport`
|
|
33
|
+
* reads from `SecurityReport.findings` by partitioning on rule +
|
|
34
|
+
* category.
|
|
35
|
+
*
|
|
36
|
+
* Both adapters land on this same `SecurityScoreInput` shape; both
|
|
37
|
+
* dispatch through the same spec; both observe identical scores.
|
|
38
|
+
*/
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.SECURITY_SCORING_SPEC = void 0;
|
|
41
|
+
/**
|
|
42
|
+
* Helper: render a count phrase with proper plural ("1 secret" /
|
|
43
|
+
* "5 secrets"). Used by penalty + cap reason builders.
|
|
44
|
+
*/
|
|
45
|
+
function plural(n, singular, plural) {
|
|
46
|
+
return `${n} ${n === 1 ? singular : (plural ?? `${singular}s`)}`;
|
|
47
|
+
}
|
|
48
|
+
exports.SECURITY_SCORING_SPEC = {
|
|
49
|
+
dimension: 'security',
|
|
50
|
+
methodology: 'iso-iec-5055-severity-dominant',
|
|
51
|
+
baseline: 100,
|
|
52
|
+
penalties: [
|
|
53
|
+
{
|
|
54
|
+
id: 'secrets-present',
|
|
55
|
+
describe: (i) => `${plural(i.secretFindings, 'hardcoded secret')} detected`,
|
|
56
|
+
applies: (i) => i.secretFindings > 0,
|
|
57
|
+
delta: (i) => (i.secretFindings > 10 ? -25 : i.secretFindings > 5 ? -20 : -15),
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: 'private-key-files',
|
|
61
|
+
describe: (i) => `${plural(i.privateKeyFiles, 'private key / cert file')} on disk`,
|
|
62
|
+
applies: (i) => i.privateKeyFiles > 0,
|
|
63
|
+
delta: () => -20,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 'env-files-in-git',
|
|
67
|
+
describe: (i) => `${plural(i.envFilesInGit, '.env file')} tracked in git`,
|
|
68
|
+
applies: (i) => i.envFilesInGit > 0,
|
|
69
|
+
delta: () => -10,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'code-findings-critical',
|
|
73
|
+
describe: (i) => `${plural(i.codeFindings.critical, 'CRITICAL code finding')} (static analysis)`,
|
|
74
|
+
applies: (i) => i.codeFindings.critical > 0,
|
|
75
|
+
delta: (i) => (i.codeFindings.critical > 10 ? -25 : i.codeFindings.critical > 5 ? -20 : -15),
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: 'code-findings-high',
|
|
79
|
+
describe: (i) => `${plural(i.codeFindings.high, 'HIGH code finding')} (static analysis)`,
|
|
80
|
+
applies: (i) => i.codeFindings.high > 0,
|
|
81
|
+
delta: (i) => (i.codeFindings.high > 5 ? -10 : -5),
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 'code-findings-medium',
|
|
85
|
+
describe: (i) => `${plural(i.codeFindings.medium, 'MEDIUM code finding')} (static analysis)`,
|
|
86
|
+
applies: (i) => i.codeFindings.medium > 10,
|
|
87
|
+
delta: () => -5,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: 'dep-vulns-critical',
|
|
91
|
+
describe: (i) => `${plural(i.depVulns.critical, 'CRITICAL dependency vulnerability')}`,
|
|
92
|
+
applies: (i) => i.depVulns.critical > 0,
|
|
93
|
+
delta: () => -15,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: 'dep-vulns-high',
|
|
97
|
+
describe: (i) => `${plural(i.depVulns.high, 'HIGH dependency vulnerability')}`,
|
|
98
|
+
applies: (i) => i.depVulns.high > 0,
|
|
99
|
+
delta: (i) => (i.depVulns.high > 5 ? -10 : -5),
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
caps: [
|
|
103
|
+
{
|
|
104
|
+
id: 'secrets-present',
|
|
105
|
+
tier: 'trust-broken',
|
|
106
|
+
describe: (i) => {
|
|
107
|
+
const parts = [];
|
|
108
|
+
if (i.secretFindings > 0)
|
|
109
|
+
parts.push(plural(i.secretFindings, 'hardcoded secret'));
|
|
110
|
+
if (i.privateKeyFiles > 0)
|
|
111
|
+
parts.push(plural(i.privateKeyFiles, 'private key file'));
|
|
112
|
+
if (i.envFilesInGit > 0)
|
|
113
|
+
parts.push(plural(i.envFilesInGit, '.env in git'));
|
|
114
|
+
return `committed credentials present: ${parts.join(' + ')}`;
|
|
115
|
+
},
|
|
116
|
+
applies: (i) => i.secretFindings > 0 || i.privateKeyFiles > 0 || i.envFilesInGit > 0,
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: 'dep-vulns-unavailable',
|
|
120
|
+
tier: 'uncertainty',
|
|
121
|
+
describe: () => `dependency vulnerability scan did not run`,
|
|
122
|
+
applies: (i) => !i.depVulnsAvailable,
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: 'high-plus-code-open',
|
|
126
|
+
tier: 'fixable-finding',
|
|
127
|
+
describe: (i) => {
|
|
128
|
+
const total = i.codeFindings.critical + i.codeFindings.high;
|
|
129
|
+
return `${plural(total, 'open HIGH+ code finding')}`;
|
|
130
|
+
},
|
|
131
|
+
applies: (i) => i.codeFindings.critical > 0 || i.codeFindings.high > 0,
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
};
|
|
135
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../../../src/scoring/dimensions/security.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Testing dimension — declarative scoring spec.
|
|
3
|
+
*
|
|
4
|
+
* Methodology: additive checklist over test-discipline signals (test
|
|
5
|
+
* ratio, coverage-config presence, runner exit code, line-coverage
|
|
6
|
+
* thresholds) gated on test-file presence, plus a hygiene penalty
|
|
7
|
+
* for source that's predominantly commented-out code.
|
|
8
|
+
*
|
|
9
|
+
* Industry-conventional coverage thresholds: 60% (adequate), 80%
|
|
10
|
+
* (excellent). Sources: CodeClimate default config, SonarQube's
|
|
11
|
+
* Coverage on New Code quality-gate condition (default 80%), Google
|
|
12
|
+
* Testing on the Toilet recommendations. These thresholds are the
|
|
13
|
+
* de-facto convention; dxkit adopts them.
|
|
14
|
+
*
|
|
15
|
+
* Cap rule encodes the Label Contract: when coverage data is absent
|
|
16
|
+
* the dimension can't honestly claim a top-tier rating regardless of
|
|
17
|
+
* how many test files exist — file presence + a green exit code
|
|
18
|
+
* without line-coverage measurement is failing the most basic
|
|
19
|
+
* testing-discipline check.
|
|
20
|
+
*
|
|
21
|
+
* unmeasured (35) no coverage data available
|
|
22
|
+
*
|
|
23
|
+
* Source signal flow: the adapter (`src/analyzers/tests/shallow.ts`)
|
|
24
|
+
* builds `TestingScoreInput` from the health-side ScoreInput
|
|
25
|
+
* (HealthMetrics + CapabilityReport) and dispatches through
|
|
26
|
+
* `evaluateSpec`. The standalone test-gaps subcommand uses its own
|
|
27
|
+
* separate analyzer; this dimension only feeds the health rollup.
|
|
28
|
+
*/
|
|
29
|
+
import type { DimensionScoringSpec } from '../spec';
|
|
30
|
+
/**
|
|
31
|
+
* Partition of every signal the Testing scorer reads. The adapter
|
|
32
|
+
* builds this shape; the spec stays consumer-agnostic.
|
|
33
|
+
*/
|
|
34
|
+
export interface TestingScoreInput {
|
|
35
|
+
/** Total source files (the denominator for test-ratio). */
|
|
36
|
+
sourceFiles: number;
|
|
37
|
+
/** Test files (discovered by name patterns per active language pack). */
|
|
38
|
+
testFiles: number;
|
|
39
|
+
/** True when at least one coverage config file is present
|
|
40
|
+
* (jest.config + collectCoverage, vitest.config + coverage,
|
|
41
|
+
* pytest.ini + --cov, etc.). */
|
|
42
|
+
coverageConfigExists: boolean;
|
|
43
|
+
/** Runner exit code: true=green, false=red, null=not invoked. */
|
|
44
|
+
testsPass: boolean | null;
|
|
45
|
+
/** Line-coverage percent (rounded integer). Null when no coverage
|
|
46
|
+
* artifact was found — the most-conservative interpretation is
|
|
47
|
+
* "we don't know" and triggers the unmeasured cap. */
|
|
48
|
+
coveragePercent: number | null;
|
|
49
|
+
/** From graphify: ratio of commented-out code in source files
|
|
50
|
+
* (0.0–1.0). Beyond 0.5 the file is more dead/commented than
|
|
51
|
+
* active code — a hygiene red flag worth penalizing. Null when
|
|
52
|
+
* graphify didn't run. */
|
|
53
|
+
commentedCodeRatio: number | null;
|
|
54
|
+
}
|
|
55
|
+
export declare const TESTING_SCORING_SPEC: DimensionScoringSpec<TestingScoreInput>;
|
|
56
|
+
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../src/scoring/dimensions/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB;;qCAEiC;IACjC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,iEAAiE;IACjE,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B;;2DAEuD;IACvD,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;;+BAG2B;IAC3B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,eAAO,MAAM,oBAAoB,EAAE,oBAAoB,CAAC,iBAAiB,CAqExE,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Testing dimension — declarative scoring spec.
|
|
4
|
+
*
|
|
5
|
+
* Methodology: additive checklist over test-discipline signals (test
|
|
6
|
+
* ratio, coverage-config presence, runner exit code, line-coverage
|
|
7
|
+
* thresholds) gated on test-file presence, plus a hygiene penalty
|
|
8
|
+
* for source that's predominantly commented-out code.
|
|
9
|
+
*
|
|
10
|
+
* Industry-conventional coverage thresholds: 60% (adequate), 80%
|
|
11
|
+
* (excellent). Sources: CodeClimate default config, SonarQube's
|
|
12
|
+
* Coverage on New Code quality-gate condition (default 80%), Google
|
|
13
|
+
* Testing on the Toilet recommendations. These thresholds are the
|
|
14
|
+
* de-facto convention; dxkit adopts them.
|
|
15
|
+
*
|
|
16
|
+
* Cap rule encodes the Label Contract: when coverage data is absent
|
|
17
|
+
* the dimension can't honestly claim a top-tier rating regardless of
|
|
18
|
+
* how many test files exist — file presence + a green exit code
|
|
19
|
+
* without line-coverage measurement is failing the most basic
|
|
20
|
+
* testing-discipline check.
|
|
21
|
+
*
|
|
22
|
+
* unmeasured (35) no coverage data available
|
|
23
|
+
*
|
|
24
|
+
* Source signal flow: the adapter (`src/analyzers/tests/shallow.ts`)
|
|
25
|
+
* builds `TestingScoreInput` from the health-side ScoreInput
|
|
26
|
+
* (HealthMetrics + CapabilityReport) and dispatches through
|
|
27
|
+
* `evaluateSpec`. The standalone test-gaps subcommand uses its own
|
|
28
|
+
* separate analyzer; this dimension only feeds the health rollup.
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.TESTING_SCORING_SPEC = void 0;
|
|
32
|
+
exports.TESTING_SCORING_SPEC = {
|
|
33
|
+
dimension: 'testing',
|
|
34
|
+
methodology: 'industry-coverage-thresholds',
|
|
35
|
+
// Additive baseline: every positive-delta signal contributes
|
|
36
|
+
// points; the zero-tests deduction surfaces the most-actionable
|
|
37
|
+
// customer case (no tests at all) with a real Top Action.
|
|
38
|
+
baseline: 0,
|
|
39
|
+
penalties: [
|
|
40
|
+
{
|
|
41
|
+
id: 'no-tests-found',
|
|
42
|
+
describe: (i) => `no test files found across ${i.sourceFiles} source files (start with the highest-risk untested files — see test-gaps)`,
|
|
43
|
+
applies: (i) => i.testFiles === 0,
|
|
44
|
+
// -60 mirrors the max bonus the test-ratio rule could grant at
|
|
45
|
+
// a healthy ratio. The score floors at 0 (E) either way, but
|
|
46
|
+
// surfacing the deduction makes the dimension actionable: the
|
|
47
|
+
// renderer shows "+60 — would lift rating E → C" and the
|
|
48
|
+
// severe-debt disclosure fires.
|
|
49
|
+
delta: () => -60,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 'test-ratio',
|
|
53
|
+
describe: (i) => `${i.testFiles} test files for ${i.sourceFiles} source files ` +
|
|
54
|
+
`(${((i.testFiles / Math.max(i.sourceFiles, 1)) * 100).toFixed(1)}% ratio)`,
|
|
55
|
+
applies: (i) => i.testFiles > 0,
|
|
56
|
+
delta: (i) => Math.min((i.testFiles / Math.max(i.sourceFiles, 1)) * 200, 60),
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'coverage-config-present',
|
|
60
|
+
describe: () => `coverage config detected`,
|
|
61
|
+
applies: (i) => i.testFiles > 0 && i.coverageConfigExists,
|
|
62
|
+
delta: () => 10,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'tests-passing',
|
|
66
|
+
describe: () => `test runner reports green`,
|
|
67
|
+
applies: (i) => i.testFiles > 0 && i.testsPass === true,
|
|
68
|
+
delta: () => 15,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: 'coverage-adequate',
|
|
72
|
+
describe: (i) => `line coverage ${i.coveragePercent}% (≥ 60% threshold met)`,
|
|
73
|
+
applies: (i) => i.testFiles > 0 && i.coveragePercent !== null && i.coveragePercent >= 60, // scoring-spec-ok: industry coverage threshold, not a rating boundary
|
|
74
|
+
delta: () => 10,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: 'coverage-excellent',
|
|
78
|
+
describe: (i) => `line coverage ${i.coveragePercent}% (≥ 80% threshold met)`,
|
|
79
|
+
applies: (i) => i.testFiles > 0 && i.coveragePercent !== null && i.coveragePercent >= 80, // scoring-spec-ok: industry coverage threshold, not a rating boundary
|
|
80
|
+
delta: () => 5,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 'commented-code-density',
|
|
84
|
+
describe: (i) => `${((i.commentedCodeRatio ?? 0) * 100).toFixed(0)}% of source is commented-out code`,
|
|
85
|
+
applies: (i) => i.commentedCodeRatio !== null && i.commentedCodeRatio > 0.5,
|
|
86
|
+
delta: () => -15,
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
caps: [
|
|
90
|
+
{
|
|
91
|
+
id: 'coverage-unmeasured',
|
|
92
|
+
tier: 'unmeasured',
|
|
93
|
+
describe: () => `no coverage data available — test runner did not produce a coverage artifact`,
|
|
94
|
+
applies: (i) => i.coveragePercent === null,
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../../../src/scoring/dimensions/testing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure-function spec evaluator. The single code path every dimension's
|
|
3
|
+
* score travels through.
|
|
4
|
+
*
|
|
5
|
+
* Same spec + same input → same `ScoreResult`, every time. No I/O, no
|
|
6
|
+
* clock, no randomness. This is the determinism property dxkit's
|
|
7
|
+
* scoring depends on for cross-process consistency and for agents to
|
|
8
|
+
* verify expected score deltas after applying a fix.
|
|
9
|
+
*
|
|
10
|
+
* Algorithm:
|
|
11
|
+
* 1. Apply each penalty whose `applies(input)` is true; accumulate
|
|
12
|
+
* deductions and a running score from `spec.baseline`.
|
|
13
|
+
* 2. Clamp the raw score to [0, 100].
|
|
14
|
+
* 3. Determine which caps apply; sort by ceiling ascending; the
|
|
15
|
+
* first (lowest-ceiling) cap that binds (i.e. final > ceiling)
|
|
16
|
+
* lowers the final score to that ceiling.
|
|
17
|
+
* 4. Compute uplift for each surfaced action:
|
|
18
|
+
* - For deductions: bounded by the current cap (0 if a cap binds).
|
|
19
|
+
* - For the binding cap: distance to the next-applicable ceiling
|
|
20
|
+
* OR the post-clamp rawScore, whichever is lower.
|
|
21
|
+
* 5. Build `topActions` by sorting deductions + cap by uplift desc.
|
|
22
|
+
* Annotate any action whose uplift crosses a rating boundary.
|
|
23
|
+
*/
|
|
24
|
+
import type { DimensionScoringSpec } from './spec';
|
|
25
|
+
import type { ScoreResult } from './result';
|
|
26
|
+
export declare function evaluateSpec<TInput>(spec: DimensionScoringSpec<TInput>, input: TInput): ScoreResult;
|
|
27
|
+
//# sourceMappingURL=evaluator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluator.d.ts","sourceRoot":"","sources":["../../src/scoring/evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAEnD,OAAO,KAAK,EAAyB,WAAW,EAAa,MAAM,UAAU,CAAC;AAE9E,wBAAgB,YAAY,CAAC,MAAM,EACjC,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,EAClC,KAAK,EAAE,MAAM,GACZ,WAAW,CAwGb"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Pure-function spec evaluator. The single code path every dimension's
|
|
4
|
+
* score travels through.
|
|
5
|
+
*
|
|
6
|
+
* Same spec + same input → same `ScoreResult`, every time. No I/O, no
|
|
7
|
+
* clock, no randomness. This is the determinism property dxkit's
|
|
8
|
+
* scoring depends on for cross-process consistency and for agents to
|
|
9
|
+
* verify expected score deltas after applying a fix.
|
|
10
|
+
*
|
|
11
|
+
* Algorithm:
|
|
12
|
+
* 1. Apply each penalty whose `applies(input)` is true; accumulate
|
|
13
|
+
* deductions and a running score from `spec.baseline`.
|
|
14
|
+
* 2. Clamp the raw score to [0, 100].
|
|
15
|
+
* 3. Determine which caps apply; sort by ceiling ascending; the
|
|
16
|
+
* first (lowest-ceiling) cap that binds (i.e. final > ceiling)
|
|
17
|
+
* lowers the final score to that ceiling.
|
|
18
|
+
* 4. Compute uplift for each surfaced action:
|
|
19
|
+
* - For deductions: bounded by the current cap (0 if a cap binds).
|
|
20
|
+
* - For the binding cap: distance to the next-applicable ceiling
|
|
21
|
+
* OR the post-clamp rawScore, whichever is lower.
|
|
22
|
+
* 5. Build `topActions` by sorting deductions + cap by uplift desc.
|
|
23
|
+
* Annotate any action whose uplift crosses a rating boundary.
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.evaluateSpec = evaluateSpec;
|
|
27
|
+
const thresholds_1 = require("./thresholds");
|
|
28
|
+
function evaluateSpec(spec, input) {
|
|
29
|
+
const deductions = [];
|
|
30
|
+
let runningScore = spec.baseline;
|
|
31
|
+
for (const rule of spec.penalties) {
|
|
32
|
+
if (!rule.applies(input))
|
|
33
|
+
continue;
|
|
34
|
+
const delta = rule.delta(input);
|
|
35
|
+
runningScore += delta;
|
|
36
|
+
const upliftIfFixed = rule.upliftIfFixed ? rule.upliftIfFixed(input) : Math.abs(delta);
|
|
37
|
+
deductions.push({
|
|
38
|
+
id: rule.id,
|
|
39
|
+
reason: rule.describe(input),
|
|
40
|
+
delta,
|
|
41
|
+
upliftIfFixed,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const rawScore = runningScore;
|
|
45
|
+
const rawPenalty = rawScore - spec.baseline;
|
|
46
|
+
const scoreAfterClamp = Math.round(Math.max(0, Math.min(100, rawScore)));
|
|
47
|
+
const applicableCaps = spec.caps
|
|
48
|
+
.filter((cap) => cap.applies(input))
|
|
49
|
+
.map((cap) => ({ cap, ceiling: thresholds_1.CAP_TIERS[cap.tier] }))
|
|
50
|
+
.sort((a, b) => a.ceiling - b.ceiling);
|
|
51
|
+
let finalScore = scoreAfterClamp;
|
|
52
|
+
let bindingCap = null;
|
|
53
|
+
for (let i = 0; i < applicableCaps.length; i++) {
|
|
54
|
+
const { cap, ceiling } = applicableCaps[i];
|
|
55
|
+
if (finalScore <= ceiling)
|
|
56
|
+
continue;
|
|
57
|
+
// Uplift if THIS cap were lifted: next-most-aggressive cap takes
|
|
58
|
+
// over, or the unclamped post-penalty score (capped at 100) bounds
|
|
59
|
+
// if no other cap applies.
|
|
60
|
+
const nextCap = applicableCaps[i + 1];
|
|
61
|
+
const ceilingIfRemoved = nextCap ? Math.min(scoreAfterClamp, nextCap.ceiling) : scoreAfterClamp;
|
|
62
|
+
bindingCap = {
|
|
63
|
+
id: cap.id,
|
|
64
|
+
tier: cap.tier,
|
|
65
|
+
ceiling,
|
|
66
|
+
reason: cap.describe(input),
|
|
67
|
+
upliftIfRemoved: ceilingIfRemoved - ceiling,
|
|
68
|
+
};
|
|
69
|
+
finalScore = ceiling;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
const capsApplied = bindingCap ? [bindingCap] : [];
|
|
73
|
+
// Compute effective uplift for each deduction. When a cap binds,
|
|
74
|
+
// fixing a non-cap deduction can't raise the score past the ceiling,
|
|
75
|
+
// so uplift reads as 0 — surfaces the cap as the real top action.
|
|
76
|
+
const effectiveDeductionUplift = (d) => {
|
|
77
|
+
if (bindingCap)
|
|
78
|
+
return 0;
|
|
79
|
+
const headroom = 100 - finalScore;
|
|
80
|
+
return Math.max(0, Math.min(d.upliftIfFixed, headroom));
|
|
81
|
+
};
|
|
82
|
+
const currentRating = (0, thresholds_1.ratingFromScore)(finalScore);
|
|
83
|
+
const projectRating = (uplift) => (0, thresholds_1.ratingFromScore)(Math.min(100, finalScore + uplift));
|
|
84
|
+
const buildTopActions = () => {
|
|
85
|
+
const actions = [];
|
|
86
|
+
for (const d of deductions) {
|
|
87
|
+
const uplift = effectiveDeductionUplift(d);
|
|
88
|
+
if (uplift <= 0)
|
|
89
|
+
continue;
|
|
90
|
+
const projected = projectRating(uplift);
|
|
91
|
+
actions.push({
|
|
92
|
+
source: 'deduction',
|
|
93
|
+
id: d.id,
|
|
94
|
+
reason: d.reason,
|
|
95
|
+
upliftIfFixed: uplift,
|
|
96
|
+
ratingTransition: projected !== currentRating ? { from: currentRating, to: projected } : undefined,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (bindingCap && bindingCap.upliftIfRemoved > 0) {
|
|
100
|
+
const projected = projectRating(bindingCap.upliftIfRemoved);
|
|
101
|
+
actions.push({
|
|
102
|
+
source: 'cap',
|
|
103
|
+
id: bindingCap.id,
|
|
104
|
+
reason: bindingCap.reason,
|
|
105
|
+
upliftIfFixed: bindingCap.upliftIfRemoved,
|
|
106
|
+
ratingTransition: projected !== currentRating ? { from: currentRating, to: projected } : undefined,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
actions.sort((a, b) => b.upliftIfFixed - a.upliftIfFixed);
|
|
110
|
+
return actions;
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
dimension: spec.dimension,
|
|
114
|
+
methodology: spec.methodology,
|
|
115
|
+
rating: currentRating,
|
|
116
|
+
score: finalScore,
|
|
117
|
+
rawScore,
|
|
118
|
+
rawPenalty,
|
|
119
|
+
deductions,
|
|
120
|
+
capsApplied,
|
|
121
|
+
topActions: buildTopActions(),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=evaluator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluator.js","sourceRoot":"","sources":["../../src/scoring/evaluator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renderer helpers — turn a `ScoreResult`'s structured provenance
|
|
3
|
+
* into markdown the customer can act on.
|
|
4
|
+
*
|
|
5
|
+
* These functions don't know which dimension they're rendering; they
|
|
6
|
+
* read `topActions[]` + `capsApplied[]` from any spec output and
|
|
7
|
+
* produce consistent prose. Per-dimension renderers (the analyzer
|
|
8
|
+
* subdirs) call into here so the "Top Actions" surface looks the
|
|
9
|
+
* same across every dimension's report.
|
|
10
|
+
*/
|
|
11
|
+
import type { CapApplied, ScoreResult, TopAction } from './result';
|
|
12
|
+
/**
|
|
13
|
+
* Subset of `DimensionScore` the formatters need. Lets the health-side
|
|
14
|
+
* `DimensionScore` and any future direct `ScoreResult` consumer share
|
|
15
|
+
* the same renderer without coupling on the full health type.
|
|
16
|
+
*/
|
|
17
|
+
export interface ScoreResultLike {
|
|
18
|
+
readonly score: number;
|
|
19
|
+
readonly rating: ScoreResult['rating'];
|
|
20
|
+
readonly rawScore?: number;
|
|
21
|
+
readonly rawPenalty?: number;
|
|
22
|
+
readonly capsApplied?: readonly CapApplied[];
|
|
23
|
+
readonly topActions?: readonly TopAction[];
|
|
24
|
+
}
|
|
25
|
+
/** One-line top-action summary, suitable for table cells / CLI grids. */
|
|
26
|
+
export declare function formatTopActionLine(score: ScoreResultLike): string;
|
|
27
|
+
/**
|
|
28
|
+
* Markdown block listing the top N actions for a dimension. Returns
|
|
29
|
+
* an empty array (no lines) when the dimension has no actionable
|
|
30
|
+
* items — caller decides whether to suppress the section header in
|
|
31
|
+
* that case.
|
|
32
|
+
*/
|
|
33
|
+
export declare function formatTopActionsBlock(score: ScoreResultLike, limit?: number): string[];
|
|
34
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/scoring/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAEnE;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC7C,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;CAC5C;AAED,yEAAyE;AACzE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAQlE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,SAAI,GAAG,MAAM,EAAE,CAmCjF"}
|