@vyuhlabs/dxkit 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +272 -0
- package/README.md +272 -358
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/dist/analyzers/developer/detailed.d.ts +26 -0
- package/dist/analyzers/developer/detailed.d.ts.map +1 -0
- package/dist/analyzers/developer/detailed.js +193 -0
- package/dist/analyzers/developer/detailed.js.map +1 -0
- package/dist/analyzers/developer/gather.d.ts +11 -0
- package/dist/analyzers/developer/gather.d.ts.map +1 -0
- package/dist/analyzers/developer/gather.js +167 -0
- package/dist/analyzers/developer/gather.js.map +1 -0
- package/dist/analyzers/developer/index.d.ts +8 -0
- package/dist/analyzers/developer/index.d.ts.map +1 -0
- package/dist/analyzers/developer/index.js +168 -0
- package/dist/analyzers/developer/index.js.map +1 -0
- package/dist/analyzers/developer/types.d.ts +49 -0
- package/dist/analyzers/developer/types.d.ts.map +1 -0
- package/dist/analyzers/developer/types.js +6 -0
- package/dist/analyzers/developer/types.js.map +1 -0
- package/dist/analyzers/docs/shallow.d.ts +9 -0
- package/dist/analyzers/docs/shallow.d.ts.map +1 -0
- package/dist/analyzers/docs/shallow.js +8 -0
- package/dist/analyzers/docs/shallow.js.map +1 -0
- package/dist/analyzers/dx/shallow.d.ts +9 -0
- package/dist/analyzers/dx/shallow.d.ts.map +1 -0
- package/dist/analyzers/dx/shallow.js +8 -0
- package/dist/analyzers/dx/shallow.js.map +1 -0
- package/dist/analyzers/evidence.d.ts +36 -0
- package/dist/analyzers/evidence.d.ts.map +1 -0
- package/dist/analyzers/evidence.js +3 -0
- package/dist/analyzers/evidence.js.map +1 -0
- package/dist/analyzers/health/actions.d.ts +10 -0
- package/dist/analyzers/health/actions.d.ts.map +1 -0
- package/dist/analyzers/health/actions.js +284 -0
- package/dist/analyzers/health/actions.js.map +1 -0
- package/dist/analyzers/health/detailed.d.ts +26 -0
- package/dist/analyzers/health/detailed.d.ts.map +1 -0
- package/dist/analyzers/health/detailed.js +147 -0
- package/dist/analyzers/health/detailed.js.map +1 -0
- package/dist/analyzers/health.d.ts +22 -0
- package/dist/analyzers/health.d.ts.map +1 -0
- package/dist/analyzers/health.js +270 -0
- package/dist/analyzers/health.js.map +1 -0
- package/dist/analyzers/index.d.ts +3 -0
- package/dist/analyzers/index.d.ts.map +1 -0
- package/dist/analyzers/index.js +6 -0
- package/dist/analyzers/index.js.map +1 -0
- package/dist/analyzers/maintainability/shallow.d.ts +9 -0
- package/dist/analyzers/maintainability/shallow.d.ts.map +1 -0
- package/dist/analyzers/maintainability/shallow.js +8 -0
- package/dist/analyzers/maintainability/shallow.js.map +1 -0
- package/dist/analyzers/quality/actions.d.ts +5 -0
- package/dist/analyzers/quality/actions.d.ts.map +1 -0
- package/dist/analyzers/quality/actions.js +158 -0
- package/dist/analyzers/quality/actions.js.map +1 -0
- package/dist/analyzers/quality/detailed.d.ts +17 -0
- package/dist/analyzers/quality/detailed.d.ts.map +1 -0
- package/dist/analyzers/quality/detailed.js +122 -0
- package/dist/analyzers/quality/detailed.js.map +1 -0
- package/dist/analyzers/quality/gather.d.ts +38 -0
- package/dist/analyzers/quality/gather.d.ts.map +1 -0
- package/dist/analyzers/quality/gather.js +279 -0
- package/dist/analyzers/quality/gather.js.map +1 -0
- package/dist/analyzers/quality/index.d.ts +12 -0
- package/dist/analyzers/quality/index.d.ts.map +1 -0
- package/dist/analyzers/quality/index.js +281 -0
- package/dist/analyzers/quality/index.js.map +1 -0
- package/dist/analyzers/quality/shallow.d.ts +9 -0
- package/dist/analyzers/quality/shallow.d.ts.map +1 -0
- package/dist/analyzers/quality/shallow.js +8 -0
- package/dist/analyzers/quality/shallow.js.map +1 -0
- package/dist/analyzers/quality/types.d.ts +66 -0
- package/dist/analyzers/quality/types.d.ts.map +1 -0
- package/dist/analyzers/quality/types.js +3 -0
- package/dist/analyzers/quality/types.js.map +1 -0
- package/dist/analyzers/remediation.d.ts +42 -0
- package/dist/analyzers/remediation.d.ts.map +1 -0
- package/dist/analyzers/remediation.js +28 -0
- package/dist/analyzers/remediation.js.map +1 -0
- package/dist/analyzers/scoring.d.ts +32 -0
- package/dist/analyzers/scoring.d.ts.map +1 -0
- package/dist/analyzers/scoring.js +410 -0
- package/dist/analyzers/scoring.js.map +1 -0
- package/dist/analyzers/security/actions.d.ts +7 -0
- package/dist/analyzers/security/actions.d.ts.map +1 -0
- package/dist/analyzers/security/actions.js +104 -0
- package/dist/analyzers/security/actions.js.map +1 -0
- package/dist/analyzers/security/detailed.d.ts +14 -0
- package/dist/analyzers/security/detailed.d.ts.map +1 -0
- package/dist/analyzers/security/detailed.js +124 -0
- package/dist/analyzers/security/detailed.js.map +1 -0
- package/dist/analyzers/security/gather.d.ts +12 -0
- package/dist/analyzers/security/gather.d.ts.map +1 -0
- package/dist/analyzers/security/gather.js +195 -0
- package/dist/analyzers/security/gather.js.map +1 -0
- package/dist/analyzers/security/index.d.ts +8 -0
- package/dist/analyzers/security/index.d.ts.map +1 -0
- package/dist/analyzers/security/index.js +173 -0
- package/dist/analyzers/security/index.js.map +1 -0
- package/dist/analyzers/security/scoring.d.ts +29 -0
- package/dist/analyzers/security/scoring.d.ts.map +1 -0
- package/dist/analyzers/security/scoring.js +40 -0
- package/dist/analyzers/security/scoring.js.map +1 -0
- package/dist/analyzers/security/shallow.d.ts +10 -0
- package/dist/analyzers/security/shallow.d.ts.map +1 -0
- package/dist/analyzers/security/shallow.js +8 -0
- package/dist/analyzers/security/shallow.js.map +1 -0
- package/dist/analyzers/security/types.d.ts +43 -0
- package/dist/analyzers/security/types.d.ts.map +1 -0
- package/dist/analyzers/security/types.js +6 -0
- package/dist/analyzers/security/types.js.map +1 -0
- package/dist/analyzers/tests/actions.d.ts +6 -0
- package/dist/analyzers/tests/actions.d.ts.map +1 -0
- package/dist/analyzers/tests/actions.js +80 -0
- package/dist/analyzers/tests/actions.js.map +1 -0
- package/dist/analyzers/tests/detailed.d.ts +14 -0
- package/dist/analyzers/tests/detailed.d.ts.map +1 -0
- package/dist/analyzers/tests/detailed.js +121 -0
- package/dist/analyzers/tests/detailed.js.map +1 -0
- package/dist/analyzers/tests/gather.d.ts +5 -0
- package/dist/analyzers/tests/gather.d.ts.map +1 -0
- package/dist/analyzers/tests/gather.js +270 -0
- package/dist/analyzers/tests/gather.js.map +1 -0
- package/dist/analyzers/tests/import-graph.d.ts +48 -0
- package/dist/analyzers/tests/import-graph.d.ts.map +1 -0
- package/dist/analyzers/tests/import-graph.js +231 -0
- package/dist/analyzers/tests/import-graph.js.map +1 -0
- package/dist/analyzers/tests/index.d.ts +8 -0
- package/dist/analyzers/tests/index.d.ts.map +1 -0
- package/dist/analyzers/tests/index.js +247 -0
- package/dist/analyzers/tests/index.js.map +1 -0
- package/dist/analyzers/tests/scoring.d.ts +27 -0
- package/dist/analyzers/tests/scoring.d.ts.map +1 -0
- package/dist/analyzers/tests/scoring.js +38 -0
- package/dist/analyzers/tests/scoring.js.map +1 -0
- package/dist/analyzers/tests/shallow.d.ts +9 -0
- package/dist/analyzers/tests/shallow.d.ts.map +1 -0
- package/dist/analyzers/tests/shallow.js +8 -0
- package/dist/analyzers/tests/shallow.js.map +1 -0
- package/dist/analyzers/tests/types.d.ts +49 -0
- package/dist/analyzers/tests/types.d.ts.map +1 -0
- package/dist/analyzers/tests/types.js +6 -0
- package/dist/analyzers/tests/types.js.map +1 -0
- package/dist/analyzers/tools/cloc.d.ts +8 -0
- package/dist/analyzers/tools/cloc.d.ts.map +1 -0
- package/dist/analyzers/tools/cloc.js +49 -0
- package/dist/analyzers/tools/cloc.js.map +1 -0
- package/dist/analyzers/tools/coverage.d.ts +59 -0
- package/dist/analyzers/tools/coverage.d.ts.map +1 -0
- package/dist/analyzers/tools/coverage.js +280 -0
- package/dist/analyzers/tools/coverage.js.map +1 -0
- package/dist/analyzers/tools/cvss-v4-lookup.d.ts +10 -0
- package/dist/analyzers/tools/cvss-v4-lookup.d.ts.map +1 -0
- package/dist/analyzers/tools/cvss-v4-lookup.js +284 -0
- package/dist/analyzers/tools/cvss-v4-lookup.js.map +1 -0
- package/dist/analyzers/tools/cvss-v4.d.ts +24 -0
- package/dist/analyzers/tools/cvss-v4.d.ts.map +1 -0
- package/dist/analyzers/tools/cvss-v4.js +362 -0
- package/dist/analyzers/tools/cvss-v4.js.map +1 -0
- package/dist/analyzers/tools/default-exclusions.gitignore +56 -0
- package/dist/analyzers/tools/exclusions.d.ts +70 -0
- package/dist/analyzers/tools/exclusions.d.ts.map +1 -0
- package/dist/analyzers/tools/exclusions.js +250 -0
- package/dist/analyzers/tools/exclusions.js.map +1 -0
- package/dist/analyzers/tools/generic.d.ts +4 -0
- package/dist/analyzers/tools/generic.d.ts.map +1 -0
- package/dist/analyzers/tools/generic.js +198 -0
- package/dist/analyzers/tools/generic.js.map +1 -0
- package/dist/analyzers/tools/gitleaks.d.ts +8 -0
- package/dist/analyzers/tools/gitleaks.d.ts.map +1 -0
- package/dist/analyzers/tools/gitleaks.js +58 -0
- package/dist/analyzers/tools/gitleaks.js.map +1 -0
- package/dist/analyzers/tools/graphify.d.ts +4 -0
- package/dist/analyzers/tools/graphify.d.ts.map +1 -0
- package/dist/analyzers/tools/graphify.js +222 -0
- package/dist/analyzers/tools/graphify.js.map +1 -0
- package/dist/analyzers/tools/osv.d.ts +51 -0
- package/dist/analyzers/tools/osv.d.ts.map +1 -0
- package/dist/analyzers/tools/osv.js +188 -0
- package/dist/analyzers/tools/osv.js.map +1 -0
- package/dist/analyzers/tools/parallel.d.ts +8 -0
- package/dist/analyzers/tools/parallel.d.ts.map +1 -0
- package/dist/analyzers/tools/parallel.js +195 -0
- package/dist/analyzers/tools/parallel.js.map +1 -0
- package/dist/analyzers/tools/runner.d.ts +13 -0
- package/dist/analyzers/tools/runner.d.ts.map +1 -0
- package/dist/analyzers/tools/runner.js +109 -0
- package/dist/analyzers/tools/runner.js.map +1 -0
- package/dist/analyzers/tools/suppressions.d.ts +55 -0
- package/dist/analyzers/tools/suppressions.d.ts.map +1 -0
- package/dist/analyzers/tools/suppressions.js +203 -0
- package/dist/analyzers/tools/suppressions.js.map +1 -0
- package/dist/analyzers/tools/timing.d.ts +9 -0
- package/dist/analyzers/tools/timing.d.ts.map +1 -0
- package/dist/analyzers/tools/timing.js +29 -0
- package/dist/analyzers/tools/timing.js.map +1 -0
- package/dist/analyzers/tools/tool-registry.d.ts +86 -0
- package/dist/analyzers/tools/tool-registry.d.ts.map +1 -0
- package/dist/analyzers/tools/tool-registry.js +705 -0
- package/dist/analyzers/tools/tool-registry.js.map +1 -0
- package/dist/analyzers/types.d.ts +125 -0
- package/dist/analyzers/types.d.ts.map +1 -0
- package/dist/analyzers/types.js +11 -0
- package/dist/analyzers/types.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +462 -0
- package/dist/cli.js.map +1 -1
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js +24 -15
- package/dist/detect.js.map +1 -1
- package/dist/languages/csharp.d.ts +5 -0
- package/dist/languages/csharp.d.ts.map +1 -0
- package/dist/languages/csharp.js +265 -0
- package/dist/languages/csharp.js.map +1 -0
- package/dist/languages/go.d.ts +11 -0
- package/dist/languages/go.d.ts.map +1 -0
- package/dist/languages/go.js +321 -0
- package/dist/languages/go.js.map +1 -0
- package/dist/languages/index.d.ts +6 -0
- package/dist/languages/index.d.ts.map +1 -0
- package/dist/languages/index.js +18 -0
- package/dist/languages/index.js.map +1 -0
- package/dist/languages/python.d.ts +3 -0
- package/dist/languages/python.d.ts.map +1 -0
- package/dist/languages/python.js +284 -0
- package/dist/languages/python.js.map +1 -0
- package/dist/languages/rust.d.ts +17 -0
- package/dist/languages/rust.d.ts.map +1 -0
- package/dist/languages/rust.js +333 -0
- package/dist/languages/rust.js.map +1 -0
- package/dist/languages/types.d.ts +38 -0
- package/dist/languages/types.d.ts.map +1 -0
- package/dist/languages/types.js +3 -0
- package/dist/languages/types.js.map +1 -0
- package/dist/languages/typescript.d.ts +15 -0
- package/dist/languages/typescript.d.ts.map +1 -0
- package/dist/languages/typescript.js +353 -0
- package/dist/languages/typescript.js.map +1 -0
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +25 -12
- package/dist/logger.js.map +1 -1
- package/dist/project-yaml.d.ts.map +1 -1
- package/dist/project-yaml.js +1 -0
- package/dist/project-yaml.js.map +1 -1
- package/dist/tools-cli.d.ts +2 -0
- package/dist/tools-cli.d.ts.map +1 -0
- package/dist/tools-cli.js +231 -0
- package/dist/tools-cli.js.map +1 -0
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -2
- package/templates/.claude/commands/dev-report.md +34 -4
- package/templates/.claude/commands/health.md +45 -2
- package/templates/.claude/commands/quality.md.template +38 -15
- package/templates/.claude/commands/test-gaps.md +36 -2
- package/templates/.claude/commands/vulnerabilities.md +36 -2
- package/templates/.project/scripts/setup/interactive-setup.sh +6 -2
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gitleaks integration -- secret scanning with 800+ patterns.
|
|
3
|
+
* Layer 2 (optional): requires `gitleaks` binary.
|
|
4
|
+
*/
|
|
5
|
+
import { HealthMetrics } from '../types';
|
|
6
|
+
/** Gather secret scanning metrics via gitleaks. */
|
|
7
|
+
export declare function gatherGitleaksMetrics(cwd: string): Partial<HealthMetrics>;
|
|
8
|
+
//# sourceMappingURL=gitleaks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitleaks.d.ts","sourceRoot":"","sources":["../../../src/analyzers/tools/gitleaks.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAczC,mDAAmD;AACnD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA4DzE"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.gatherGitleaksMetrics = gatherGitleaksMetrics;
|
|
4
|
+
const runner_1 = require("./runner");
|
|
5
|
+
const tool_registry_1 = require("./tool-registry");
|
|
6
|
+
const exclusions_1 = require("./exclusions");
|
|
7
|
+
const suppressions_1 = require("./suppressions");
|
|
8
|
+
/** Gather secret scanning metrics via gitleaks. */
|
|
9
|
+
function gatherGitleaksMetrics(cwd) {
|
|
10
|
+
const gitleaksCmd = findGitleaks(cwd);
|
|
11
|
+
if (!gitleaksCmd) {
|
|
12
|
+
return { toolsUnavailable: ['gitleaks'] };
|
|
13
|
+
}
|
|
14
|
+
// Run gitleaks with JSON report (--no-git scans files, not git history)
|
|
15
|
+
const reportPath = `/tmp/dxkit-gitleaks-${Date.now()}.json`;
|
|
16
|
+
(0, runner_1.run)(`${gitleaksCmd} detect --source '${cwd}' --report-format json --report-path '${reportPath}' --no-git --exit-code 0 2>/dev/null`, cwd, 120000);
|
|
17
|
+
// Read report file
|
|
18
|
+
const reportRaw = (0, runner_1.run)(`cat '${reportPath}' 2>/dev/null`, cwd);
|
|
19
|
+
// Clean up
|
|
20
|
+
(0, runner_1.run)(`rm -f '${reportPath}'`, cwd);
|
|
21
|
+
if (!reportRaw) {
|
|
22
|
+
return { toolsUnavailable: ['gitleaks (no output)'] };
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const findings = JSON.parse(reportRaw);
|
|
26
|
+
if (!Array.isArray(findings)) {
|
|
27
|
+
return { toolsUsed: ['gitleaks'] };
|
|
28
|
+
}
|
|
29
|
+
const secretDetails = findings.map((f) => ({
|
|
30
|
+
file: f.File.replace(cwd + '/', '').replace(cwd, ''),
|
|
31
|
+
line: f.StartLine,
|
|
32
|
+
rule: f.RuleID,
|
|
33
|
+
severity: f.RuleID.includes('private-key') ? 'critical' : 'high',
|
|
34
|
+
}));
|
|
35
|
+
// Post-filter using project exclusions. Gitleaks --no-git scans everything
|
|
36
|
+
// on disk (ignores .gitignore), so we re-apply the resolved exclusion set
|
|
37
|
+
// via the centralized isExcludedPath() predicate.
|
|
38
|
+
const filtered = secretDetails.filter((d) => !(0, exclusions_1.isExcludedPath)(cwd, d.file));
|
|
39
|
+
// Apply user-defined suppressions from `.dxkit-suppressions.json` so
|
|
40
|
+
// known-false positives (test fixtures, approved exceptions) don't count.
|
|
41
|
+
const suppressions = (0, suppressions_1.loadSuppressions)(cwd);
|
|
42
|
+
const { kept, suppressed } = (0, suppressions_1.applySuppressions)(filtered, suppressions.gitleaks, (d) => d.rule, (d) => d.file);
|
|
43
|
+
return {
|
|
44
|
+
secretFindings: kept.length,
|
|
45
|
+
secretDetails: kept,
|
|
46
|
+
secretSuppressed: suppressed.length,
|
|
47
|
+
toolsUsed: ['gitleaks'],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return { toolsUnavailable: ['gitleaks (parse error)'] };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function findGitleaks(cwd) {
|
|
55
|
+
const status = (0, tool_registry_1.findTool)(tool_registry_1.TOOL_DEFS.gitleaks, cwd);
|
|
56
|
+
return status.available ? status.path : null;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=gitleaks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitleaks.js","sourceRoot":"","sources":["../../../src/analyzers/tools/gitleaks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphify.d.ts","sourceRoot":"","sources":["../../../src/analyzers/tools/graphify.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAyIzC,+CAA+C;AAC/C,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAqDzE"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.gatherGraphifyMetrics = gatherGraphifyMetrics;
|
|
37
|
+
/**
|
|
38
|
+
* Graphify integration -- deterministic AST extraction via tree-sitter.
|
|
39
|
+
* Layer 2 (optional): requires `pip install graphifyy`.
|
|
40
|
+
*
|
|
41
|
+
* Runs graphify's Python API via subprocess, parses structured JSON output.
|
|
42
|
+
* All metrics are derived from EXTRACTED confidence edges only (no LLM).
|
|
43
|
+
*/
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const runner_1 = require("./runner");
|
|
46
|
+
const tool_registry_1 = require("./tool-registry");
|
|
47
|
+
const exclusions_1 = require("./exclusions");
|
|
48
|
+
/** Build the graphify Python script with cwd-specific exclusions baked in. */
|
|
49
|
+
function buildGraphifyScript(cwd) {
|
|
50
|
+
return `# Exclusion set derived from src/analyzers/tools/exclusions.ts
|
|
51
|
+
import json, sys, os, tempfile
|
|
52
|
+
from pathlib import Path
|
|
53
|
+
from collections import Counter
|
|
54
|
+
|
|
55
|
+
# Redirect graphify cache to /tmp so we don't pollute the target repo
|
|
56
|
+
_cache_dir = Path(tempfile.mkdtemp(prefix='dxkit-graphify-'))
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
from graphify.extract import extract, collect_files
|
|
60
|
+
from graphify.build import build
|
|
61
|
+
from graphify.cluster import cluster, score_all
|
|
62
|
+
from graphify.analyze import god_nodes
|
|
63
|
+
except ImportError:
|
|
64
|
+
print(json.dumps({"error": "graphify not installed"}))
|
|
65
|
+
sys.exit(0)
|
|
66
|
+
|
|
67
|
+
target = Path(sys.argv[1])
|
|
68
|
+
|
|
69
|
+
# collect_files doesn't exclude node_modules etc, so filter manually
|
|
70
|
+
EXCLUDE_DIRS = ${(0, exclusions_1.getPythonExcludeSet)(cwd)}
|
|
71
|
+
all_files = collect_files(target)
|
|
72
|
+
files = [f for f in all_files if not any(ex in f.parts for ex in EXCLUDE_DIRS)]
|
|
73
|
+
if not files:
|
|
74
|
+
print(json.dumps({"error": "no files found"}))
|
|
75
|
+
sys.exit(0)
|
|
76
|
+
|
|
77
|
+
# Monkey-patch cache to use /tmp instead of target repo
|
|
78
|
+
import graphify.cache as _gc
|
|
79
|
+
_gc.cache_dir = lambda root=None: _cache_dir / "cache"
|
|
80
|
+
(_cache_dir / "cache").mkdir(parents=True, exist_ok=True)
|
|
81
|
+
|
|
82
|
+
# Suppress progress output by redirecting stdout during extraction
|
|
83
|
+
import io
|
|
84
|
+
_real_stdout = sys.stdout
|
|
85
|
+
sys.stdout = io.StringIO()
|
|
86
|
+
result = extract(files)
|
|
87
|
+
sys.stdout = _real_stdout
|
|
88
|
+
G = build([result], directed=True)
|
|
89
|
+
communities = cluster(G)
|
|
90
|
+
|
|
91
|
+
# Functions vs modules
|
|
92
|
+
nodes = list(G.nodes(data=True))
|
|
93
|
+
functions = [(n, d) for n, d in nodes if "()" in d.get("label", "")]
|
|
94
|
+
modules = [(n, d) for n, d in nodes if "()" not in d.get("label", "")]
|
|
95
|
+
|
|
96
|
+
# Functions per file
|
|
97
|
+
file_funcs = Counter()
|
|
98
|
+
for n, d in functions:
|
|
99
|
+
sf = d.get("source_file", "")
|
|
100
|
+
file_funcs[sf] += 1
|
|
101
|
+
|
|
102
|
+
max_file = file_funcs.most_common(1)[0] if file_funcs else ("", 0)
|
|
103
|
+
|
|
104
|
+
# God nodes (degree > 15)
|
|
105
|
+
gods = god_nodes(G, top_n=50)
|
|
106
|
+
god_count = sum(1 for g in gods if g["edges"] > 15)
|
|
107
|
+
|
|
108
|
+
# Cohesion
|
|
109
|
+
scores = score_all(G, communities) if communities else {}
|
|
110
|
+
avg_cohesion = sum(scores.values()) / len(scores) if scores else 0.0
|
|
111
|
+
|
|
112
|
+
# Orphan modules (no inbound imports)
|
|
113
|
+
import_targets = set()
|
|
114
|
+
for u, v, data in G.edges(data=True):
|
|
115
|
+
if data.get("relation") == "imports_from":
|
|
116
|
+
import_targets.add(v)
|
|
117
|
+
module_ids = set(n for n, d in modules)
|
|
118
|
+
orphans = module_ids - import_targets
|
|
119
|
+
|
|
120
|
+
# Dead imports (imported but never called)
|
|
121
|
+
call_targets = set()
|
|
122
|
+
for u, v, data in G.edges(data=True):
|
|
123
|
+
if data.get("relation") == "calls":
|
|
124
|
+
call_targets.add(v)
|
|
125
|
+
dead = import_targets - call_targets - module_ids
|
|
126
|
+
|
|
127
|
+
# Commented code ratio: source files with 0 function/class AST nodes
|
|
128
|
+
source_files_set = set()
|
|
129
|
+
files_with_nodes = set()
|
|
130
|
+
for n, d in nodes:
|
|
131
|
+
sf = d.get("source_file", "")
|
|
132
|
+
if sf:
|
|
133
|
+
source_files_set.add(sf)
|
|
134
|
+
if "()" in d.get("label", "") or any(
|
|
135
|
+
data.get("relation") == "method"
|
|
136
|
+
for _, _, data in G.edges(n, data=True)
|
|
137
|
+
):
|
|
138
|
+
files_with_nodes.add(sf)
|
|
139
|
+
|
|
140
|
+
total_src = len(source_files_set)
|
|
141
|
+
empty_files = total_src - len(files_with_nodes)
|
|
142
|
+
commented_ratio = empty_files / total_src if total_src > 0 else 0.0
|
|
143
|
+
|
|
144
|
+
# Clean up temp cache
|
|
145
|
+
import shutil
|
|
146
|
+
shutil.rmtree(str(_cache_dir), ignore_errors=True)
|
|
147
|
+
|
|
148
|
+
print(json.dumps({
|
|
149
|
+
"functionCount": len(functions),
|
|
150
|
+
"classCount": len([n for n, d in modules if any(
|
|
151
|
+
data.get("relation") == "method" for _, _, data in G.edges(n, data=True)
|
|
152
|
+
)]),
|
|
153
|
+
"maxFunctionsInFile": max_file[1] if max_file else 0,
|
|
154
|
+
"maxFunctionsFilePath": str(max_file[0]) if max_file else "",
|
|
155
|
+
"godNodeCount": god_count,
|
|
156
|
+
"communityCount": len(communities),
|
|
157
|
+
"avgCohesion": round(avg_cohesion, 3),
|
|
158
|
+
"orphanModuleCount": len(orphans),
|
|
159
|
+
"deadImportCount": len(dead),
|
|
160
|
+
"commentedCodeRatio": round(commented_ratio, 3),
|
|
161
|
+
"sourceFilesInGraph": total_src,
|
|
162
|
+
}))
|
|
163
|
+
`;
|
|
164
|
+
}
|
|
165
|
+
/** Gather AST-derived metrics via graphify. */
|
|
166
|
+
function gatherGraphifyMetrics(cwd) {
|
|
167
|
+
// findPython already verifies graphify is importable
|
|
168
|
+
const pythonCmd = findPython(cwd);
|
|
169
|
+
if (!pythonCmd) {
|
|
170
|
+
return { toolsUnavailable: ['graphify (not installed)'] };
|
|
171
|
+
}
|
|
172
|
+
// Write script to temp file to avoid shell escaping issues
|
|
173
|
+
const scriptPath = `/tmp/dxkit-graphify-${Date.now()}.py`;
|
|
174
|
+
fs.writeFileSync(scriptPath, buildGraphifyScript(cwd));
|
|
175
|
+
// Redirect stderr to suppress progress output, run from /tmp to avoid writing to target
|
|
176
|
+
const output = (0, runner_1.run)(`cd /tmp && ${pythonCmd} '${scriptPath}' '${cwd}' 2>/dev/null`, cwd, 120000);
|
|
177
|
+
try {
|
|
178
|
+
fs.unlinkSync(scriptPath);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
/* ignore */
|
|
182
|
+
}
|
|
183
|
+
if (!output) {
|
|
184
|
+
return { toolsUnavailable: ['graphify (failed to run)'] };
|
|
185
|
+
}
|
|
186
|
+
// Graphify prints progress to stdout before the JSON — extract only the JSON line
|
|
187
|
+
const jsonLine = output
|
|
188
|
+
.split('\n')
|
|
189
|
+
.filter((l) => l.startsWith('{'))
|
|
190
|
+
.pop();
|
|
191
|
+
if (!jsonLine) {
|
|
192
|
+
return { toolsUnavailable: ['graphify (no JSON output)'] };
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const data = JSON.parse(jsonLine);
|
|
196
|
+
if (data.error) {
|
|
197
|
+
return { toolsUnavailable: [`graphify (${data.error})`] };
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
functionCount: data.functionCount,
|
|
201
|
+
classCount: data.classCount,
|
|
202
|
+
maxFunctionsInFile: data.maxFunctionsInFile,
|
|
203
|
+
maxFunctionsFilePath: data.maxFunctionsFilePath,
|
|
204
|
+
godNodeCount: data.godNodeCount,
|
|
205
|
+
communityCount: data.communityCount,
|
|
206
|
+
avgCohesion: data.avgCohesion,
|
|
207
|
+
orphanModuleCount: data.orphanModuleCount,
|
|
208
|
+
deadImportCount: data.deadImportCount,
|
|
209
|
+
commentedCodeRatio: data.commentedCodeRatio,
|
|
210
|
+
toolsUsed: ['graphify'],
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return { toolsUnavailable: ['graphify (parse error)'] };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/** Find a working python3 that has graphify installed. Delegates to tool-registry. */
|
|
218
|
+
function findPython(cwd) {
|
|
219
|
+
const status = (0, tool_registry_1.findTool)(tool_registry_1.TOOL_DEFS.graphify, cwd);
|
|
220
|
+
return status.available ? status.path : null;
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=graphify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphify.js","sourceRoot":"","sources":["../../../src/analyzers/tools/graphify.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkJA,sDAqDC;AAvMD;;;;;;GAMG;AACH,uCAAyB;AAEzB,qCAA+B;AAC/B,mDAAsD;AACtD,6CAAmD;AAgBnD,8EAA8E;AAC9E,SAAS,mBAAmB,CAAC,GAAW;IACtC,OAAO;;;;;;;;;;;;;;;;;;;;iBAoBQ,IAAA,gCAAmB,EAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6FxC,CAAC;AACF,CAAC;AAED,+CAA+C;AAC/C,SAAgB,qBAAqB,CAAC,GAAW;IAC/C,qDAAqD;IACrD,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,EAAE,gBAAgB,EAAE,CAAC,0BAA0B,CAAC,EAAE,CAAC;IAC5D,CAAC;IAED,2DAA2D;IAC3D,MAAM,UAAU,GAAG,uBAAuB,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC;IAC1D,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;IACvD,wFAAwF;IACxF,MAAM,MAAM,GAAG,IAAA,YAAG,EAAC,cAAc,SAAS,KAAK,UAAU,MAAM,GAAG,eAAe,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAChG,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,gBAAgB,EAAE,CAAC,0BAA0B,CAAC,EAAE,CAAC;IAC5D,CAAC;IAED,kFAAkF;IAClF,MAAM,QAAQ,GAAG,MAAM;SACpB,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;SAChC,GAAG,EAAE,CAAC;IACT,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,gBAAgB,EAAE,CAAC,2BAA2B,CAAC,EAAE,CAAC;IAC7D,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAwC,CAAC;QACzE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,gBAAgB,EAAE,CAAC,aAAa,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;QAC5D,CAAC;QAED,OAAO;YACL,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;YAC3C,oBAAoB,EAAE,IAAI,CAAC,oBAAoB;YAC/C,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;YAC3C,SAAS,EAAE,CAAC,UAAU,CAAC;SACxB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,gBAAgB,EAAE,CAAC,wBAAwB,CAAC,EAAE,CAAC;IAC1D,CAAC;AACH,CAAC;AAED,sFAAsF;AACtF,SAAS,UAAU,CAAC,GAAW;IAC7B,MAAM,MAAM,GAAG,IAAA,wBAAQ,EAAC,yBAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IACjD,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OSV.dev severity enrichment.
|
|
3
|
+
*
|
|
4
|
+
* Several dependency scanners (pip-audit, govulncheck) report vulnerabilities
|
|
5
|
+
* without per-finding severity tiers. This module looks up the vulnerability
|
|
6
|
+
* IDs against https://api.osv.dev/v1/vulns/{id} and classifies them into
|
|
7
|
+
* critical/high/medium/low buckets.
|
|
8
|
+
*
|
|
9
|
+
* Offline safety: if the API is unreachable or an ID is unknown, the caller
|
|
10
|
+
* falls back to a default bucket (pip-audit → medium, govulncheck → high).
|
|
11
|
+
* The analyzer must never fail because OSV was slow.
|
|
12
|
+
*/
|
|
13
|
+
export type Severity = 'critical' | 'high' | 'medium' | 'low' | 'unknown';
|
|
14
|
+
export interface OsvVuln {
|
|
15
|
+
id?: string;
|
|
16
|
+
severity?: Array<{
|
|
17
|
+
type: string;
|
|
18
|
+
score: string;
|
|
19
|
+
}>;
|
|
20
|
+
database_specific?: {
|
|
21
|
+
severity?: string;
|
|
22
|
+
};
|
|
23
|
+
affected?: Array<{
|
|
24
|
+
severity?: Array<{
|
|
25
|
+
type: string;
|
|
26
|
+
score: string;
|
|
27
|
+
}>;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
/** NVD CVSS 3.x base-score bands. */
|
|
31
|
+
export declare function scoreToTier(score: number): Severity;
|
|
32
|
+
/**
|
|
33
|
+
* Minimal CVSS v3.0/3.1 base-score calculator.
|
|
34
|
+
* Spec: https://www.first.org/cvss/v3.1/specification-document#7-1-Base-Metrics-Equations
|
|
35
|
+
* Returns null if the vector is malformed or missing required metrics.
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseCvssV3BaseScore(vector: string): number | null;
|
|
38
|
+
/** Classify a single OSV record. Prefers CVSS vector, then database_specific string. */
|
|
39
|
+
export declare function classifyOsvSeverity(vuln: OsvVuln): Severity;
|
|
40
|
+
/** Signature of the fetcher — swapped in tests to avoid real network. */
|
|
41
|
+
export type OsvFetcher = (id: string) => Promise<OsvVuln | null>;
|
|
42
|
+
/**
|
|
43
|
+
* Look up severities for a batch of vuln IDs.
|
|
44
|
+
* Runs requests in parallel, session-caches results, returns a map keyed by ID.
|
|
45
|
+
* IDs that fail (network error, 404, unparseable) map to 'unknown' — caller
|
|
46
|
+
* uses a per-scanner default bucket for those.
|
|
47
|
+
*/
|
|
48
|
+
export declare function enrichSeverities(ids: string[], fetcher?: OsvFetcher): Promise<Map<string, Severity>>;
|
|
49
|
+
/** Test-only — reset the process cache between tests. */
|
|
50
|
+
export declare function __clearOsvCache(): void;
|
|
51
|
+
//# sourceMappingURL=osv.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"osv.d.ts","sourceRoot":"","sources":["../../../src/analyzers/tools/osv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;AAE1E,MAAM,WAAW,OAAO;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClD,iBAAiB,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,QAAQ,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACnD,CAAC,CAAC;CACJ;AAKD,qCAAqC;AACrC,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAMnD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA2ClE;AAED,wFAAwF;AACxF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAiC3D;AAED,yEAAyE;AACzE,MAAM,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;AAwBjE;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EAAE,EACb,OAAO,GAAE,UAA4B,GACpC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CA2BhC;AAED,yDAAyD;AACzD,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OSV.dev severity enrichment.
|
|
4
|
+
*
|
|
5
|
+
* Several dependency scanners (pip-audit, govulncheck) report vulnerabilities
|
|
6
|
+
* without per-finding severity tiers. This module looks up the vulnerability
|
|
7
|
+
* IDs against https://api.osv.dev/v1/vulns/{id} and classifies them into
|
|
8
|
+
* critical/high/medium/low buckets.
|
|
9
|
+
*
|
|
10
|
+
* Offline safety: if the API is unreachable or an ID is unknown, the caller
|
|
11
|
+
* falls back to a default bucket (pip-audit → medium, govulncheck → high).
|
|
12
|
+
* The analyzer must never fail because OSV was slow.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.scoreToTier = scoreToTier;
|
|
16
|
+
exports.parseCvssV3BaseScore = parseCvssV3BaseScore;
|
|
17
|
+
exports.classifyOsvSeverity = classifyOsvSeverity;
|
|
18
|
+
exports.enrichSeverities = enrichSeverities;
|
|
19
|
+
exports.__clearOsvCache = __clearOsvCache;
|
|
20
|
+
const cvss_v4_1 = require("./cvss-v4");
|
|
21
|
+
/** Process-scoped cache so repeated lookups in a session don't re-query. */
|
|
22
|
+
const cache = new Map();
|
|
23
|
+
/** NVD CVSS 3.x base-score bands. */
|
|
24
|
+
function scoreToTier(score) {
|
|
25
|
+
if (score >= 9.0)
|
|
26
|
+
return 'critical';
|
|
27
|
+
if (score >= 7.0)
|
|
28
|
+
return 'high';
|
|
29
|
+
if (score >= 4.0)
|
|
30
|
+
return 'medium';
|
|
31
|
+
if (score > 0.0)
|
|
32
|
+
return 'low';
|
|
33
|
+
return 'unknown';
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Minimal CVSS v3.0/3.1 base-score calculator.
|
|
37
|
+
* Spec: https://www.first.org/cvss/v3.1/specification-document#7-1-Base-Metrics-Equations
|
|
38
|
+
* Returns null if the vector is malformed or missing required metrics.
|
|
39
|
+
*/
|
|
40
|
+
function parseCvssV3BaseScore(vector) {
|
|
41
|
+
if (!vector.startsWith('CVSS:3.'))
|
|
42
|
+
return null;
|
|
43
|
+
const parts = new Map();
|
|
44
|
+
for (const kv of vector.split('/').slice(1)) {
|
|
45
|
+
const [k, v] = kv.split(':');
|
|
46
|
+
if (k && v)
|
|
47
|
+
parts.set(k, v);
|
|
48
|
+
}
|
|
49
|
+
// Required base metrics
|
|
50
|
+
const AV = parts.get('AV');
|
|
51
|
+
const AC = parts.get('AC');
|
|
52
|
+
const PR = parts.get('PR');
|
|
53
|
+
const UI = parts.get('UI');
|
|
54
|
+
const S = parts.get('S');
|
|
55
|
+
const C = parts.get('C');
|
|
56
|
+
const I = parts.get('I');
|
|
57
|
+
const A = parts.get('A');
|
|
58
|
+
if (!AV || !AC || !PR || !UI || !S || !C || !I || !A)
|
|
59
|
+
return null;
|
|
60
|
+
const avWeights = { N: 0.85, A: 0.62, L: 0.55, P: 0.2 };
|
|
61
|
+
const acWeights = { L: 0.77, H: 0.44 };
|
|
62
|
+
const prUnchanged = { N: 0.85, L: 0.62, H: 0.27 };
|
|
63
|
+
const prChanged = { N: 0.85, L: 0.68, H: 0.5 };
|
|
64
|
+
const uiWeights = { N: 0.85, R: 0.62 };
|
|
65
|
+
const ciaWeights = { H: 0.56, L: 0.22, N: 0 };
|
|
66
|
+
const av = avWeights[AV];
|
|
67
|
+
const ac = acWeights[AC];
|
|
68
|
+
const pr = S === 'C' ? prChanged[PR] : prUnchanged[PR];
|
|
69
|
+
const ui = uiWeights[UI];
|
|
70
|
+
const conf = ciaWeights[C];
|
|
71
|
+
const integ = ciaWeights[I];
|
|
72
|
+
const avail = ciaWeights[A];
|
|
73
|
+
if ([av, ac, pr, ui, conf, integ, avail].some((x) => x === undefined))
|
|
74
|
+
return null;
|
|
75
|
+
const iss = 1 - (1 - conf) * (1 - integ) * (1 - avail);
|
|
76
|
+
const impact = S === 'C' ? 7.52 * (iss - 0.029) - 3.25 * Math.pow(iss - 0.02, 15) : 6.42 * iss;
|
|
77
|
+
if (impact <= 0)
|
|
78
|
+
return 0;
|
|
79
|
+
const exploitability = 8.22 * av * ac * pr * ui;
|
|
80
|
+
const raw = S === 'C' ? 1.08 * (impact + exploitability) : impact + exploitability;
|
|
81
|
+
const base = Math.min(raw, 10);
|
|
82
|
+
// CVSS "round up to one decimal" (ceil to nearest 0.1)
|
|
83
|
+
return Math.ceil(base * 10) / 10;
|
|
84
|
+
}
|
|
85
|
+
/** Classify a single OSV record. Prefers CVSS vector, then database_specific string. */
|
|
86
|
+
function classifyOsvSeverity(vuln) {
|
|
87
|
+
// Collect CVSS_V4 + CVSS_V3 entries (top level and inside affected[].severity[]).
|
|
88
|
+
// V4 is preferred when available since modern CVEs (2025+) increasingly use V4 only.
|
|
89
|
+
const v4 = [];
|
|
90
|
+
const v3 = [];
|
|
91
|
+
const collect = (entries) => {
|
|
92
|
+
for (const s of entries ?? []) {
|
|
93
|
+
if (!s.score)
|
|
94
|
+
continue;
|
|
95
|
+
if (s.type === 'CVSS_V4')
|
|
96
|
+
v4.push(s.score);
|
|
97
|
+
else if (s.type === 'CVSS_V3')
|
|
98
|
+
v3.push(s.score);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
collect(vuln.severity);
|
|
102
|
+
for (const a of vuln.affected ?? [])
|
|
103
|
+
collect(a.severity);
|
|
104
|
+
let maxScore = -1;
|
|
105
|
+
for (const vec of v4) {
|
|
106
|
+
const score = (0, cvss_v4_1.parseCvssV4BaseScore)(vec);
|
|
107
|
+
if (score !== null && score > maxScore)
|
|
108
|
+
maxScore = score;
|
|
109
|
+
}
|
|
110
|
+
for (const vec of v3) {
|
|
111
|
+
const score = parseCvssV3BaseScore(vec);
|
|
112
|
+
if (score !== null && score > maxScore)
|
|
113
|
+
maxScore = score;
|
|
114
|
+
}
|
|
115
|
+
if (maxScore >= 0)
|
|
116
|
+
return scoreToTier(maxScore);
|
|
117
|
+
// Fallback: database_specific.severity string (common on GHSA records)
|
|
118
|
+
const ds = vuln.database_specific?.severity?.toUpperCase();
|
|
119
|
+
if (ds === 'CRITICAL')
|
|
120
|
+
return 'critical';
|
|
121
|
+
if (ds === 'HIGH')
|
|
122
|
+
return 'high';
|
|
123
|
+
if (ds === 'MEDIUM' || ds === 'MODERATE')
|
|
124
|
+
return 'medium';
|
|
125
|
+
if (ds === 'LOW')
|
|
126
|
+
return 'low';
|
|
127
|
+
return 'unknown';
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Per-request timeout. Must be generous enough that concurrent analyzer tools
|
|
131
|
+
* (gitleaks, semgrep, cloc) don't starve the fetches — 5s proved too aggressive
|
|
132
|
+
* under full-analyzer load. Unreachable hosts still fail fast via AbortSignal.
|
|
133
|
+
*/
|
|
134
|
+
const OSV_REQUEST_TIMEOUT_MS = 10000;
|
|
135
|
+
const DEFAULT_FETCHER = async (id) => {
|
|
136
|
+
try {
|
|
137
|
+
const res = await fetch(`https://api.osv.dev/v1/vulns/${encodeURIComponent(id)}`, {
|
|
138
|
+
signal: AbortSignal.timeout(OSV_REQUEST_TIMEOUT_MS),
|
|
139
|
+
});
|
|
140
|
+
if (!res.ok)
|
|
141
|
+
return null;
|
|
142
|
+
return (await res.json());
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
if (process.env.DXKIT_DEBUG_OSV) {
|
|
146
|
+
process.stderr.write(`[dxkit-osv] ${id}: ${err.message}\n`);
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Look up severities for a batch of vuln IDs.
|
|
153
|
+
* Runs requests in parallel, session-caches results, returns a map keyed by ID.
|
|
154
|
+
* IDs that fail (network error, 404, unparseable) map to 'unknown' — caller
|
|
155
|
+
* uses a per-scanner default bucket for those.
|
|
156
|
+
*/
|
|
157
|
+
async function enrichSeverities(ids, fetcher = DEFAULT_FETCHER) {
|
|
158
|
+
const result = new Map();
|
|
159
|
+
const toFetch = [];
|
|
160
|
+
for (const id of ids) {
|
|
161
|
+
if (cache.has(id)) {
|
|
162
|
+
result.set(id, cache.get(id));
|
|
163
|
+
}
|
|
164
|
+
else if (!toFetch.includes(id)) {
|
|
165
|
+
toFetch.push(id);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (toFetch.length === 0)
|
|
169
|
+
return result;
|
|
170
|
+
const settled = await Promise.allSettled(toFetch.map(async (id) => {
|
|
171
|
+
const vuln = await fetcher(id);
|
|
172
|
+
const sev = vuln ? classifyOsvSeverity(vuln) : 'unknown';
|
|
173
|
+
return [id, sev];
|
|
174
|
+
}));
|
|
175
|
+
for (const p of settled) {
|
|
176
|
+
if (p.status === 'fulfilled') {
|
|
177
|
+
const [id, sev] = p.value;
|
|
178
|
+
cache.set(id, sev);
|
|
179
|
+
result.set(id, sev);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
/** Test-only — reset the process cache between tests. */
|
|
185
|
+
function __clearOsvCache() {
|
|
186
|
+
cache.clear();
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=osv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"osv.js","sourceRoot":"","sources":["../../../src/analyzers/tools/osv.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { HealthMetrics } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Run cloc + gitleaks + graphify gather functions in parallel child processes.
|
|
4
|
+
* Each child calls the real gather function from the existing tool module.
|
|
5
|
+
* Falls back to sequential on low memory (<1GB free).
|
|
6
|
+
*/
|
|
7
|
+
export declare function gatherLayer2Parallel(cwd: string, verbose?: boolean): Partial<HealthMetrics>;
|
|
8
|
+
//# sourceMappingURL=parallel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallel.d.ts","sourceRoot":"","sources":["../../../src/analyzers/tools/parallel.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AASzC;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC,aAAa,CAAC,CAoFzF"}
|