@defai.digital/ax-cli 3.4.6 → 3.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +2 -6
- package/README.md +109 -2
- package/dist/analyzers/ast/index.d.ts +9 -0
- package/dist/analyzers/ast/index.js +10 -0
- package/dist/analyzers/ast/index.js.map +1 -0
- package/dist/analyzers/ast/node-helpers.d.ts +81 -0
- package/dist/analyzers/ast/node-helpers.js +128 -0
- package/dist/analyzers/ast/node-helpers.js.map +1 -0
- package/dist/analyzers/ast/parser.d.ts +59 -0
- package/dist/analyzers/ast/parser.js +293 -0
- package/dist/analyzers/ast/parser.js.map +1 -0
- package/dist/analyzers/ast/traverser.d.ts +67 -0
- package/dist/analyzers/ast/traverser.js +156 -0
- package/dist/analyzers/ast/traverser.js.map +1 -0
- package/dist/analyzers/ast/types.d.ts +107 -0
- package/dist/analyzers/ast/types.js +7 -0
- package/dist/analyzers/ast/types.js.map +1 -0
- package/dist/analyzers/best-practices/index.d.ts +10 -0
- package/dist/analyzers/best-practices/index.js +11 -0
- package/dist/analyzers/best-practices/index.js.map +1 -0
- package/dist/analyzers/code-smells/base-smell-detector.d.ts +30 -0
- package/dist/analyzers/code-smells/base-smell-detector.js +44 -0
- package/dist/analyzers/code-smells/base-smell-detector.js.map +1 -0
- package/dist/analyzers/code-smells/code-smell-analyzer.d.ts +30 -0
- package/dist/analyzers/code-smells/code-smell-analyzer.js +167 -0
- package/dist/analyzers/code-smells/code-smell-analyzer.js.map +1 -0
- package/dist/analyzers/code-smells/detectors/data-clumps-detector.d.ts +11 -0
- package/dist/analyzers/code-smells/detectors/data-clumps-detector.js +66 -0
- package/dist/analyzers/code-smells/detectors/data-clumps-detector.js.map +1 -0
- package/dist/analyzers/code-smells/detectors/dead-code-detector.d.ts +11 -0
- package/dist/analyzers/code-smells/detectors/dead-code-detector.js +53 -0
- package/dist/analyzers/code-smells/detectors/dead-code-detector.js.map +1 -0
- package/dist/analyzers/code-smells/detectors/duplicate-code-detector.d.ts +11 -0
- package/dist/analyzers/code-smells/detectors/duplicate-code-detector.js +51 -0
- package/dist/analyzers/code-smells/detectors/duplicate-code-detector.js.map +1 -0
- package/dist/analyzers/code-smells/detectors/feature-envy-detector.d.ts +11 -0
- package/dist/analyzers/code-smells/detectors/feature-envy-detector.js +64 -0
- package/dist/analyzers/code-smells/detectors/feature-envy-detector.js.map +1 -0
- package/dist/analyzers/code-smells/detectors/inappropriate-intimacy-detector.d.ts +11 -0
- package/dist/analyzers/code-smells/detectors/inappropriate-intimacy-detector.js +56 -0
- package/dist/analyzers/code-smells/detectors/inappropriate-intimacy-detector.js.map +1 -0
- package/dist/analyzers/code-smells/detectors/large-class-detector.d.ts +13 -0
- package/dist/analyzers/code-smells/detectors/large-class-detector.js +58 -0
- package/dist/analyzers/code-smells/detectors/large-class-detector.js.map +1 -0
- package/dist/analyzers/code-smells/detectors/long-method-detector.d.ts +12 -0
- package/dist/analyzers/code-smells/detectors/long-method-detector.js +52 -0
- package/dist/analyzers/code-smells/detectors/long-method-detector.js.map +1 -0
- package/dist/analyzers/code-smells/detectors/long-parameter-list-detector.d.ts +12 -0
- package/dist/analyzers/code-smells/detectors/long-parameter-list-detector.js +50 -0
- package/dist/analyzers/code-smells/detectors/long-parameter-list-detector.js.map +1 -0
- package/dist/analyzers/code-smells/detectors/magic-numbers-detector.d.ts +12 -0
- package/dist/analyzers/code-smells/detectors/magic-numbers-detector.js +54 -0
- package/dist/analyzers/code-smells/detectors/magic-numbers-detector.js.map +1 -0
- package/dist/analyzers/code-smells/detectors/nested-conditionals-detector.d.ts +13 -0
- package/dist/analyzers/code-smells/detectors/nested-conditionals-detector.js +71 -0
- package/dist/analyzers/code-smells/detectors/nested-conditionals-detector.js.map +1 -0
- package/dist/analyzers/code-smells/index.d.ts +16 -0
- package/dist/analyzers/code-smells/index.js +19 -0
- package/dist/analyzers/code-smells/index.js.map +1 -0
- package/dist/analyzers/code-smells/types.d.ts +82 -0
- package/dist/analyzers/code-smells/types.js +30 -0
- package/dist/analyzers/code-smells/types.js.map +1 -0
- package/dist/analyzers/dependency/circular-detector.d.ts +17 -0
- package/dist/analyzers/dependency/circular-detector.js +71 -0
- package/dist/analyzers/dependency/circular-detector.js.map +1 -0
- package/dist/analyzers/dependency/coupling-calculator.d.ts +24 -0
- package/dist/analyzers/dependency/coupling-calculator.js +86 -0
- package/dist/analyzers/dependency/coupling-calculator.js.map +1 -0
- package/dist/analyzers/dependency/dependency-analyzer.d.ts +40 -0
- package/dist/analyzers/dependency/dependency-analyzer.js +214 -0
- package/dist/analyzers/dependency/dependency-analyzer.js.map +1 -0
- package/dist/analyzers/dependency/dependency-graph.d.ts +57 -0
- package/dist/analyzers/dependency/dependency-graph.js +186 -0
- package/dist/analyzers/dependency/dependency-graph.js.map +1 -0
- package/dist/analyzers/dependency/index.d.ts +8 -0
- package/dist/analyzers/dependency/index.js +8 -0
- package/dist/analyzers/dependency/index.js.map +1 -0
- package/dist/analyzers/dependency/types.d.ts +105 -0
- package/dist/analyzers/dependency/types.js +5 -0
- package/dist/analyzers/dependency/types.js.map +1 -0
- package/dist/analyzers/git/churn-calculator.d.ts +34 -0
- package/dist/analyzers/git/churn-calculator.js +214 -0
- package/dist/analyzers/git/churn-calculator.js.map +1 -0
- package/dist/analyzers/git/git-analyzer.d.ts +19 -0
- package/dist/analyzers/git/git-analyzer.js +71 -0
- package/dist/analyzers/git/git-analyzer.js.map +1 -0
- package/dist/analyzers/git/hotspot-detector.d.ts +34 -0
- package/dist/analyzers/git/hotspot-detector.js +170 -0
- package/dist/analyzers/git/hotspot-detector.js.map +1 -0
- package/dist/analyzers/git/index.d.ts +7 -0
- package/dist/analyzers/git/index.js +7 -0
- package/dist/analyzers/git/index.js.map +1 -0
- package/dist/analyzers/git/types.d.ts +88 -0
- package/dist/analyzers/git/types.js +5 -0
- package/dist/analyzers/git/types.js.map +1 -0
- package/dist/analyzers/metrics/halstead-calculator.d.ts +30 -0
- package/dist/analyzers/metrics/halstead-calculator.js +150 -0
- package/dist/analyzers/metrics/halstead-calculator.js.map +1 -0
- package/dist/analyzers/metrics/index.d.ts +9 -0
- package/dist/analyzers/metrics/index.js +9 -0
- package/dist/analyzers/metrics/index.js.map +1 -0
- package/dist/analyzers/metrics/maintainability-calculator.d.ts +17 -0
- package/dist/analyzers/metrics/maintainability-calculator.js +46 -0
- package/dist/analyzers/metrics/maintainability-calculator.js.map +1 -0
- package/dist/analyzers/metrics/metrics-analyzer.d.ts +32 -0
- package/dist/analyzers/metrics/metrics-analyzer.js +140 -0
- package/dist/analyzers/metrics/metrics-analyzer.js.map +1 -0
- package/dist/analyzers/metrics/types.d.ts +67 -0
- package/dist/analyzers/metrics/types.js +5 -0
- package/dist/analyzers/metrics/types.js.map +1 -0
- package/dist/analyzers/security/base-detector.d.ts +58 -0
- package/dist/analyzers/security/base-detector.js +104 -0
- package/dist/analyzers/security/base-detector.js.map +1 -0
- package/dist/analyzers/security/detectors/command-injection-detector.d.ts +12 -0
- package/dist/analyzers/security/detectors/command-injection-detector.js +84 -0
- package/dist/analyzers/security/detectors/command-injection-detector.js.map +1 -0
- package/dist/analyzers/security/detectors/hardcoded-secrets-detector.d.ts +16 -0
- package/dist/analyzers/security/detectors/hardcoded-secrets-detector.js +140 -0
- package/dist/analyzers/security/detectors/hardcoded-secrets-detector.js.map +1 -0
- package/dist/analyzers/security/detectors/insecure-deserialization-detector.d.ts +12 -0
- package/dist/analyzers/security/detectors/insecure-deserialization-detector.js +109 -0
- package/dist/analyzers/security/detectors/insecure-deserialization-detector.js.map +1 -0
- package/dist/analyzers/security/detectors/insecure-random-detector.d.ts +12 -0
- package/dist/analyzers/security/detectors/insecure-random-detector.js +61 -0
- package/dist/analyzers/security/detectors/insecure-random-detector.js.map +1 -0
- package/dist/analyzers/security/detectors/path-traversal-detector.d.ts +12 -0
- package/dist/analyzers/security/detectors/path-traversal-detector.js +82 -0
- package/dist/analyzers/security/detectors/path-traversal-detector.js.map +1 -0
- package/dist/analyzers/security/detectors/sql-injection-detector.d.ts +12 -0
- package/dist/analyzers/security/detectors/sql-injection-detector.js +88 -0
- package/dist/analyzers/security/detectors/sql-injection-detector.js.map +1 -0
- package/dist/analyzers/security/detectors/weak-crypto-detector.d.ts +12 -0
- package/dist/analyzers/security/detectors/weak-crypto-detector.js +104 -0
- package/dist/analyzers/security/detectors/weak-crypto-detector.js.map +1 -0
- package/dist/analyzers/security/detectors/xss-detector.d.ts +12 -0
- package/dist/analyzers/security/detectors/xss-detector.js +90 -0
- package/dist/analyzers/security/detectors/xss-detector.js.map +1 -0
- package/dist/analyzers/security/index.d.ts +16 -0
- package/dist/analyzers/security/index.js +18 -0
- package/dist/analyzers/security/index.js.map +1 -0
- package/dist/analyzers/security/security-analyzer.d.ts +38 -0
- package/dist/analyzers/security/security-analyzer.js +215 -0
- package/dist/analyzers/security/security-analyzer.js.map +1 -0
- package/dist/analyzers/security/types.d.ts +95 -0
- package/dist/analyzers/security/types.js +7 -0
- package/dist/analyzers/security/types.js.map +1 -0
- package/dist/hooks/use-enhanced-input.d.ts +0 -1
- package/dist/hooks/use-enhanced-input.js.map +1 -1
- package/dist/index.js +0 -0
- package/dist/mcp/validation.js +12 -6
- package/dist/mcp/validation.js.map +1 -1
- package/dist/tools/analysis-tools.d.ts +73 -0
- package/dist/tools/analysis-tools.js +422 -0
- package/dist/tools/analysis-tools.js.map +1 -0
- package/dist/tools/bash.js +2 -1
- package/dist/tools/bash.js.map +1 -1
- package/dist/ui/components/toast-notification.js +0 -1
- package/dist/ui/components/toast-notification.js.map +1 -1
- package/dist/ui/components/welcome-panel.js +1 -1
- package/dist/ui/components/welcome-panel.js.map +1 -1
- package/dist/ui/hooks/use-input-history.d.ts +9 -0
- package/dist/ui/hooks/use-input-history.js +117 -0
- package/dist/ui/hooks/use-input-history.js.map +1 -0
- package/dist/utils/parallel-analyzer.js +30 -17
- package/dist/utils/parallel-analyzer.js.map +1 -1
- package/eslint.config.js +3 -0
- package/package.json +5 -5
- package/vitest.config.ts +1 -0
- package/.ax-cli/checkpoints/2025-11-20/checkpoint-11e9e0ba-c39d-4fd2-aa77-bc818811c921.json +0 -69
- package/.ax-cli/checkpoints/2025-11-20/checkpoint-2b260b98-b418-4c7c-9694-e2b94967e662.json +0 -24
- package/.ax-cli/checkpoints/2025-11-20/checkpoint-7e03601e-e8ab-4cd7-9841-a74b66adf78f.json +0 -69
- package/.ax-cli/checkpoints/2025-11-20/checkpoint-7f9c6562-771f-4fd0-adcf-9e7e9ac34ae8.json +0 -44
- package/.ax-cli/checkpoints/2025-11-20/checkpoint-e1ebe666-4c3a-4367-ba5c-27fe512a9c70.json +0 -24
- package/.ax-cli/checkpoints/2025-11-21/checkpoint-15743e7d-430c-4d76-b6fc-955d7a5c250c.json +0 -44
- package/.ax-cli/checkpoints/2025-11-21/checkpoint-25cf7679-0b3f-4988-83d7-704548fbba91.json +0 -69
- package/.ax-cli/checkpoints/2025-11-21/checkpoint-54aedbac-6db0-464e-8ebb-dbb3979e6dca.json +0 -24
- package/.ax-cli/checkpoints/2025-11-21/checkpoint-7658aed8-fe5d-4222-903f-1a7c63717ea7.json +0 -24
- package/.ax-cli/checkpoints/2025-11-21/checkpoint-c9c13497-40dc-4294-a327-6a5fc854eaa1.json +0 -69
- package/automatosx.config.json +0 -333
- package/config/messages.yaml +0 -75
- package/config/models.yaml +0 -66
- package/config/prompts.yaml +0 -156
- package/config/settings.yaml +0 -86
- package/dist/commands/weather.d.ts +0 -8
- package/dist/commands/weather.js +0 -160
- package/dist/commands/weather.js.map +0 -1
- package/dist/grok/client.d.ts +0 -144
- package/dist/grok/client.js +0 -237
- package/dist/grok/client.js.map +0 -1
- package/dist/grok/tools.d.ts +0 -8
- package/dist/grok/tools.js +0 -318
- package/dist/grok/tools.js.map +0 -1
- package/dist/grok/types.d.ts +0 -291
- package/dist/grok/types.js +0 -127
- package/dist/grok/types.js.map +0 -1
- package/dist/tools/morph-editor.d.ts +0 -36
- package/dist/tools/morph-editor.js +0 -308
- package/dist/tools/morph-editor.js.map +0 -1
- package/dist/ui/components/session-recovery.d.ts +0 -12
- package/dist/ui/components/session-recovery.js +0 -93
- package/dist/ui/components/session-recovery.js.map +0 -1
- package/dist/utils/model-config.d.ts +0 -28
- package/dist/utils/model-config.js +0 -43
- package/dist/utils/model-config.js.map +0 -1
- package/dist/utils/tool-helpers.d.ts +0 -25
- package/dist/utils/tool-helpers.js +0 -79
- package/dist/utils/tool-helpers.js.map +0 -1
- package/packages/schemas/dist/index.d.ts +0 -14
- package/packages/schemas/dist/index.d.ts.map +0 -1
- package/packages/schemas/dist/index.js +0 -19
- package/packages/schemas/dist/index.js.map +0 -1
- package/packages/schemas/dist/public/core/brand-types.d.ts +0 -308
- package/packages/schemas/dist/public/core/brand-types.d.ts.map +0 -1
- package/packages/schemas/dist/public/core/brand-types.js +0 -243
- package/packages/schemas/dist/public/core/brand-types.js.map +0 -1
- package/packages/schemas/dist/public/core/enums.d.ts +0 -227
- package/packages/schemas/dist/public/core/enums.d.ts.map +0 -1
- package/packages/schemas/dist/public/core/enums.js +0 -222
- package/packages/schemas/dist/public/core/enums.js.map +0 -1
- package/packages/schemas/dist/public/core/id-types.d.ts +0 -286
- package/packages/schemas/dist/public/core/id-types.d.ts.map +0 -1
- package/packages/schemas/dist/public/core/id-types.js +0 -136
- package/packages/schemas/dist/public/core/id-types.js.map +0 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maintainability Index Calculator
|
|
3
|
+
*
|
|
4
|
+
* Calculates MI = 171 - 5.2*ln(V) - 0.23*CC - 16.2*ln(LOC)
|
|
5
|
+
* Normalized to 0-100 scale
|
|
6
|
+
*/
|
|
7
|
+
export class MaintainabilityCalculator {
|
|
8
|
+
/**
|
|
9
|
+
* Calculate Maintainability Index
|
|
10
|
+
*/
|
|
11
|
+
calculateIndex(halsteadVolume, cyclomaticComplexity, linesOfCode) {
|
|
12
|
+
// Original formula: MI = 171 - 5.2*ln(V) - 0.23*CC - 16.2*ln(LOC)
|
|
13
|
+
// Clamp values to avoid invalid log
|
|
14
|
+
const V = Math.max(1, halsteadVolume);
|
|
15
|
+
const CC = Math.max(1, cyclomaticComplexity);
|
|
16
|
+
const LOC = Math.max(1, linesOfCode);
|
|
17
|
+
const rawMI = 171 - 5.2 * Math.log(V) - 0.23 * CC - 16.2 * Math.log(LOC);
|
|
18
|
+
// Normalize to 0-100 scale
|
|
19
|
+
// Original MI can range from negative to ~171
|
|
20
|
+
// We'll use: MI_normalized = max(0, (rawMI / 171) * 100)
|
|
21
|
+
const score = Math.max(0, Math.min(100, (rawMI / 171) * 100));
|
|
22
|
+
const rating = this.getRating(score);
|
|
23
|
+
return Object.freeze({
|
|
24
|
+
score: Math.round(score * 100) / 100,
|
|
25
|
+
rating,
|
|
26
|
+
halsteadVolume: V,
|
|
27
|
+
cyclomaticComplexity: CC,
|
|
28
|
+
linesOfCode: LOC,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get letter rating from MI score
|
|
33
|
+
*/
|
|
34
|
+
getRating(score) {
|
|
35
|
+
if (score >= 80)
|
|
36
|
+
return 'A'; // Highly maintainable
|
|
37
|
+
if (score >= 65)
|
|
38
|
+
return 'B'; // Moderately maintainable
|
|
39
|
+
if (score >= 50)
|
|
40
|
+
return 'C'; // Somewhat maintainable
|
|
41
|
+
if (score >= 35)
|
|
42
|
+
return 'D'; // Difficult to maintain
|
|
43
|
+
return 'F'; // Very difficult to maintain
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=maintainability-calculator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maintainability-calculator.js","sourceRoot":"","sources":["../../../src/analyzers/metrics/maintainability-calculator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,OAAO,yBAAyB;IACpC;;OAEG;IACH,cAAc,CACZ,cAAsB,EACtB,oBAA4B,EAC5B,WAAmB;QAEnB,kEAAkE;QAClE,oCAAoC;QACpC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;QACtC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;QAErC,MAAM,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEzE,2BAA2B;QAC3B,8CAA8C;QAC9C,yDAAyD;QACzD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QAE9D,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAErC,OAAO,MAAM,CAAC,MAAM,CAAC;YACnB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG;YACpC,MAAM;YACN,cAAc,EAAE,CAAC;YACjB,oBAAoB,EAAE,EAAE;YACxB,WAAW,EAAE,GAAG;SACjB,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,SAAS,CAAC,KAAa;QAC7B,IAAI,KAAK,IAAI,EAAE;YAAE,OAAO,GAAG,CAAC,CAAC,sBAAsB;QACnD,IAAI,KAAK,IAAI,EAAE;YAAE,OAAO,GAAG,CAAC,CAAC,0BAA0B;QACvD,IAAI,KAAK,IAAI,EAAE;YAAE,OAAO,GAAG,CAAC,CAAC,wBAAwB;QACrD,IAAI,KAAK,IAAI,EAAE;YAAE,OAAO,GAAG,CAAC,CAAC,wBAAwB;QACrD,OAAO,GAAG,CAAC,CAAC,6BAA6B;IAC3C,CAAC;CACF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Main orchestrator for advanced code metrics analysis
|
|
5
|
+
*/
|
|
6
|
+
import type { MetricsAnalysisResult, MetricsAnalysisOptions } from './types.js';
|
|
7
|
+
export declare class MetricsAnalyzer {
|
|
8
|
+
private halsteadCalculator;
|
|
9
|
+
private maintainabilityCalculator;
|
|
10
|
+
private astParser;
|
|
11
|
+
constructor();
|
|
12
|
+
/**
|
|
13
|
+
* Analyze metrics for files matching patterns
|
|
14
|
+
*/
|
|
15
|
+
analyze(directory: string, options?: MetricsAnalysisOptions): Promise<MetricsAnalysisResult>;
|
|
16
|
+
/**
|
|
17
|
+
* Analyze a single file
|
|
18
|
+
*/
|
|
19
|
+
private analyzeFile;
|
|
20
|
+
/**
|
|
21
|
+
* Calculate lines of code (excluding blank lines)
|
|
22
|
+
*/
|
|
23
|
+
private calculateLinesOfCode;
|
|
24
|
+
/**
|
|
25
|
+
* Get files to analyze based on patterns
|
|
26
|
+
*/
|
|
27
|
+
private getFilesToAnalyze;
|
|
28
|
+
/**
|
|
29
|
+
* Calculate summary statistics
|
|
30
|
+
*/
|
|
31
|
+
private calculateSummary;
|
|
32
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Main orchestrator for advanced code metrics analysis
|
|
5
|
+
*/
|
|
6
|
+
import { HalsteadCalculator } from './halstead-calculator.js';
|
|
7
|
+
import { MaintainabilityCalculator } from './maintainability-calculator.js';
|
|
8
|
+
import { ASTParser } from '../ast/parser.js';
|
|
9
|
+
import { glob } from 'glob';
|
|
10
|
+
export class MetricsAnalyzer {
|
|
11
|
+
halsteadCalculator;
|
|
12
|
+
maintainabilityCalculator;
|
|
13
|
+
astParser;
|
|
14
|
+
constructor() {
|
|
15
|
+
this.halsteadCalculator = new HalsteadCalculator();
|
|
16
|
+
this.maintainabilityCalculator = new MaintainabilityCalculator();
|
|
17
|
+
this.astParser = new ASTParser();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Analyze metrics for files matching patterns
|
|
21
|
+
*/
|
|
22
|
+
async analyze(directory, options = {}) {
|
|
23
|
+
const files = await this.getFilesToAnalyze(directory, options);
|
|
24
|
+
const fileMetrics = [];
|
|
25
|
+
for (const filePath of files) {
|
|
26
|
+
try {
|
|
27
|
+
const metrics = await this.analyzeFile(filePath);
|
|
28
|
+
fileMetrics.push(metrics);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
// Skip files that fail to parse
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const summary = this.calculateSummary(fileMetrics);
|
|
36
|
+
return Object.freeze({
|
|
37
|
+
fileMetrics: Object.freeze(fileMetrics),
|
|
38
|
+
summary,
|
|
39
|
+
timestamp: new Date(),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Analyze a single file
|
|
44
|
+
*/
|
|
45
|
+
async analyzeFile(filePath) {
|
|
46
|
+
// Calculate Halstead metrics
|
|
47
|
+
const halstead = this.halsteadCalculator.calculateMetrics(filePath);
|
|
48
|
+
// Get AST info for complexity and LOC
|
|
49
|
+
const ast = this.astParser.parseFile(filePath);
|
|
50
|
+
// Calculate average and max complexity
|
|
51
|
+
const complexities = ast.functions.map((f) => f.complexity);
|
|
52
|
+
const averageComplexity = complexities.length > 0
|
|
53
|
+
? complexities.reduce((a, b) => a + b, 0) / complexities.length
|
|
54
|
+
: 0;
|
|
55
|
+
const maxComplexity = complexities.length > 0 ? Math.max(...complexities) : 0;
|
|
56
|
+
// Calculate total lines of code (excluding blank lines and comments)
|
|
57
|
+
const linesOfCode = this.calculateLinesOfCode(filePath);
|
|
58
|
+
// Calculate Maintainability Index
|
|
59
|
+
const maintainability = this.maintainabilityCalculator.calculateIndex(halstead.volume, averageComplexity, linesOfCode);
|
|
60
|
+
return Object.freeze({
|
|
61
|
+
filePath,
|
|
62
|
+
halstead,
|
|
63
|
+
maintainability,
|
|
64
|
+
averageComplexity: Math.round(averageComplexity * 100) / 100,
|
|
65
|
+
maxComplexity,
|
|
66
|
+
totalFunctions: ast.functions.length,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Calculate lines of code (excluding blank lines)
|
|
71
|
+
*/
|
|
72
|
+
calculateLinesOfCode(filePath) {
|
|
73
|
+
const sourceFile = this.astParser.getSourceFile(filePath);
|
|
74
|
+
const text = sourceFile.getFullText();
|
|
75
|
+
const lines = text.split('\n');
|
|
76
|
+
// Count non-blank lines
|
|
77
|
+
let loc = 0;
|
|
78
|
+
for (const line of lines) {
|
|
79
|
+
const trimmed = line.trim();
|
|
80
|
+
if (trimmed.length > 0) {
|
|
81
|
+
loc++;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return loc;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get files to analyze based on patterns
|
|
88
|
+
*/
|
|
89
|
+
async getFilesToAnalyze(directory, options) {
|
|
90
|
+
const includePatterns = options.includePatterns || ['**/*.ts', '**/*.tsx'];
|
|
91
|
+
const excludePatterns = options.excludePatterns || [
|
|
92
|
+
'**/node_modules/**',
|
|
93
|
+
'**/*.test.ts',
|
|
94
|
+
'**/*.spec.ts',
|
|
95
|
+
'**/dist/**',
|
|
96
|
+
'**/build/**',
|
|
97
|
+
];
|
|
98
|
+
const allFiles = new Set();
|
|
99
|
+
for (const pattern of includePatterns) {
|
|
100
|
+
const matches = await glob(pattern, {
|
|
101
|
+
cwd: directory,
|
|
102
|
+
absolute: true,
|
|
103
|
+
ignore: excludePatterns ? [...excludePatterns] : [],
|
|
104
|
+
});
|
|
105
|
+
for (const match of matches) {
|
|
106
|
+
allFiles.add(match);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return Array.from(allFiles).sort();
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Calculate summary statistics
|
|
113
|
+
*/
|
|
114
|
+
calculateSummary(fileMetrics) {
|
|
115
|
+
if (fileMetrics.length === 0) {
|
|
116
|
+
return Object.freeze({
|
|
117
|
+
filesAnalyzed: 0,
|
|
118
|
+
averageMaintainability: 0,
|
|
119
|
+
averageHalsteadVolume: 0,
|
|
120
|
+
averageComplexity: 0,
|
|
121
|
+
lowMaintainabilityCount: 0,
|
|
122
|
+
highComplexityCount: 0,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
const totalMaintainability = fileMetrics.reduce((sum, m) => sum + m.maintainability.score, 0);
|
|
126
|
+
const totalHalsteadVolume = fileMetrics.reduce((sum, m) => sum + m.halstead.volume, 0);
|
|
127
|
+
const totalComplexity = fileMetrics.reduce((sum, m) => sum + m.averageComplexity, 0);
|
|
128
|
+
const lowMaintainabilityCount = fileMetrics.filter((m) => m.maintainability.score < 65).length;
|
|
129
|
+
const highComplexityCount = fileMetrics.filter((m) => m.maxComplexity > 10).length;
|
|
130
|
+
return Object.freeze({
|
|
131
|
+
filesAnalyzed: fileMetrics.length,
|
|
132
|
+
averageMaintainability: Math.round((totalMaintainability / fileMetrics.length) * 100) / 100,
|
|
133
|
+
averageHalsteadVolume: Math.round((totalHalsteadVolume / fileMetrics.length) * 100) / 100,
|
|
134
|
+
averageComplexity: Math.round((totalComplexity / fileMetrics.length) * 100) / 100,
|
|
135
|
+
lowMaintainabilityCount,
|
|
136
|
+
highComplexityCount,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=metrics-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics-analyzer.js","sourceRoot":"","sources":["../../../src/analyzers/metrics/metrics-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advanced Metrics Types
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Halstead complexity metrics
|
|
6
|
+
*/
|
|
7
|
+
export interface HalsteadMetrics {
|
|
8
|
+
readonly n1: number;
|
|
9
|
+
readonly n2: number;
|
|
10
|
+
readonly N1: number;
|
|
11
|
+
readonly N2: number;
|
|
12
|
+
readonly vocabulary: number;
|
|
13
|
+
readonly length: number;
|
|
14
|
+
readonly calculatedLength: number;
|
|
15
|
+
readonly volume: number;
|
|
16
|
+
readonly difficulty: number;
|
|
17
|
+
readonly effort: number;
|
|
18
|
+
readonly time: number;
|
|
19
|
+
readonly bugs: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Maintainability Index
|
|
23
|
+
*/
|
|
24
|
+
export interface MaintainabilityIndex {
|
|
25
|
+
readonly score: number;
|
|
26
|
+
readonly rating: 'A' | 'B' | 'C' | 'D' | 'F';
|
|
27
|
+
readonly halsteadVolume: number;
|
|
28
|
+
readonly cyclomaticComplexity: number;
|
|
29
|
+
readonly linesOfCode: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* File metrics
|
|
33
|
+
*/
|
|
34
|
+
export interface FileMetrics {
|
|
35
|
+
readonly filePath: string;
|
|
36
|
+
readonly halstead: HalsteadMetrics;
|
|
37
|
+
readonly maintainability: MaintainabilityIndex;
|
|
38
|
+
readonly averageComplexity: number;
|
|
39
|
+
readonly maxComplexity: number;
|
|
40
|
+
readonly totalFunctions: number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Metrics analysis result
|
|
44
|
+
*/
|
|
45
|
+
export interface MetricsAnalysisResult {
|
|
46
|
+
readonly fileMetrics: ReadonlyArray<FileMetrics>;
|
|
47
|
+
readonly summary: MetricsSummary;
|
|
48
|
+
readonly timestamp: Date;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Summary statistics
|
|
52
|
+
*/
|
|
53
|
+
export interface MetricsSummary {
|
|
54
|
+
readonly filesAnalyzed: number;
|
|
55
|
+
readonly averageMaintainability: number;
|
|
56
|
+
readonly averageHalsteadVolume: number;
|
|
57
|
+
readonly averageComplexity: number;
|
|
58
|
+
readonly lowMaintainabilityCount: number;
|
|
59
|
+
readonly highComplexityCount: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Analysis options
|
|
63
|
+
*/
|
|
64
|
+
export interface MetricsAnalysisOptions {
|
|
65
|
+
readonly includePatterns?: readonly string[];
|
|
66
|
+
readonly excludePatterns?: readonly string[];
|
|
67
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/analyzers/metrics/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Security Detector
|
|
3
|
+
*
|
|
4
|
+
* Abstract base class for security vulnerability detectors
|
|
5
|
+
*/
|
|
6
|
+
import type { SecurityDetector, SecurityVulnerability, SecuritySeverity, OWASPCategory } from './types.js';
|
|
7
|
+
export declare abstract class BaseSecurityDetector implements SecurityDetector {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly description: string;
|
|
11
|
+
readonly severity: SecuritySeverity;
|
|
12
|
+
readonly owaspCategory?: OWASPCategory;
|
|
13
|
+
readonly cweId?: string;
|
|
14
|
+
readonly enabled: boolean;
|
|
15
|
+
protected readonly fileExtensions: readonly string[];
|
|
16
|
+
constructor(config: {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
description: string;
|
|
20
|
+
severity: SecuritySeverity;
|
|
21
|
+
owaspCategory?: OWASPCategory;
|
|
22
|
+
cweId?: string;
|
|
23
|
+
fileExtensions?: readonly string[];
|
|
24
|
+
enabled?: boolean;
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* Check if detector applies to this file type
|
|
28
|
+
*/
|
|
29
|
+
appliesTo(filePath: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Scan file content for vulnerabilities
|
|
32
|
+
*/
|
|
33
|
+
abstract scan(content: string, filePath: string): Promise<SecurityVulnerability[]>;
|
|
34
|
+
/**
|
|
35
|
+
* Create a vulnerability finding
|
|
36
|
+
*/
|
|
37
|
+
protected createVulnerability(file: string, line: number, code: string, description: string, recommendation: string, references?: string[]): SecurityVulnerability;
|
|
38
|
+
/**
|
|
39
|
+
* Find line number for a match in content
|
|
40
|
+
*/
|
|
41
|
+
protected findLineNumber(content: string, matchIndex: number): number;
|
|
42
|
+
/**
|
|
43
|
+
* Extract code snippet around a match
|
|
44
|
+
*/
|
|
45
|
+
protected extractCodeSnippet(content: string, matchIndex: number, contextLines?: number): string;
|
|
46
|
+
/**
|
|
47
|
+
* Check if line is in a comment
|
|
48
|
+
*/
|
|
49
|
+
protected isInComment(content: string, matchIndex: number): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Check if match is in a string literal
|
|
52
|
+
*/
|
|
53
|
+
protected isInString(content: string, matchIndex: number): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Check if match should be ignored
|
|
56
|
+
*/
|
|
57
|
+
protected shouldIgnore(content: string, matchIndex: number): boolean;
|
|
58
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Security Detector
|
|
3
|
+
*
|
|
4
|
+
* Abstract base class for security vulnerability detectors
|
|
5
|
+
*/
|
|
6
|
+
import path from 'path';
|
|
7
|
+
export class BaseSecurityDetector {
|
|
8
|
+
id;
|
|
9
|
+
name;
|
|
10
|
+
description;
|
|
11
|
+
severity;
|
|
12
|
+
owaspCategory;
|
|
13
|
+
cweId;
|
|
14
|
+
enabled;
|
|
15
|
+
fileExtensions;
|
|
16
|
+
constructor(config) {
|
|
17
|
+
this.id = config.id;
|
|
18
|
+
this.name = config.name;
|
|
19
|
+
this.description = config.description;
|
|
20
|
+
this.severity = config.severity;
|
|
21
|
+
this.owaspCategory = config.owaspCategory;
|
|
22
|
+
this.cweId = config.cweId;
|
|
23
|
+
this.fileExtensions = config.fileExtensions || ['.ts', '.tsx', '.js', '.jsx'];
|
|
24
|
+
this.enabled = config.enabled !== false;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Check if detector applies to this file type
|
|
28
|
+
*/
|
|
29
|
+
appliesTo(filePath) {
|
|
30
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
31
|
+
return this.fileExtensions.includes(ext);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create a vulnerability finding
|
|
35
|
+
*/
|
|
36
|
+
createVulnerability(file, line, code, description, recommendation, references = []) {
|
|
37
|
+
return Object.freeze({
|
|
38
|
+
id: this.id,
|
|
39
|
+
name: this.name,
|
|
40
|
+
description,
|
|
41
|
+
severity: this.severity,
|
|
42
|
+
owaspCategory: this.owaspCategory,
|
|
43
|
+
cweId: this.cweId,
|
|
44
|
+
file,
|
|
45
|
+
line,
|
|
46
|
+
code: code.trim(),
|
|
47
|
+
recommendation,
|
|
48
|
+
references: Object.freeze(references),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Find line number for a match in content
|
|
53
|
+
*/
|
|
54
|
+
findLineNumber(content, matchIndex) {
|
|
55
|
+
const beforeMatch = content.substring(0, matchIndex);
|
|
56
|
+
return beforeMatch.split('\n').length;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Extract code snippet around a match
|
|
60
|
+
*/
|
|
61
|
+
extractCodeSnippet(content, matchIndex, contextLines = 0) {
|
|
62
|
+
const lines = content.split('\n');
|
|
63
|
+
const lineNumber = this.findLineNumber(content, matchIndex);
|
|
64
|
+
const startLine = Math.max(0, lineNumber - contextLines - 1);
|
|
65
|
+
const endLine = Math.min(lines.length, lineNumber + contextLines);
|
|
66
|
+
return lines.slice(startLine, endLine).join('\n');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check if line is in a comment
|
|
70
|
+
*/
|
|
71
|
+
isInComment(content, matchIndex) {
|
|
72
|
+
const beforeMatch = content.substring(0, matchIndex);
|
|
73
|
+
const lastLineBreak = beforeMatch.lastIndexOf('\n');
|
|
74
|
+
const currentLine = content.substring(lastLineBreak + 1, matchIndex + 50);
|
|
75
|
+
// Check for single-line comment
|
|
76
|
+
if (currentLine.includes('//')) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
// Check for multi-line comment
|
|
80
|
+
const openComments = (beforeMatch.match(/\/\*/g) || []).length;
|
|
81
|
+
const closeComments = (beforeMatch.match(/\*\//g) || []).length;
|
|
82
|
+
return openComments > closeComments;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Check if match is in a string literal
|
|
86
|
+
*/
|
|
87
|
+
isInString(content, matchIndex) {
|
|
88
|
+
const beforeMatch = content.substring(0, matchIndex);
|
|
89
|
+
const lastLineBreak = beforeMatch.lastIndexOf('\n');
|
|
90
|
+
const lineContent = beforeMatch.substring(lastLineBreak + 1);
|
|
91
|
+
// Count unescaped quotes
|
|
92
|
+
const singleQuotes = (lineContent.match(/(?<!\\)'/g) || []).length;
|
|
93
|
+
const doubleQuotes = (lineContent.match(/(?<!\\)"/g) || []).length;
|
|
94
|
+
const backticks = (lineContent.match(/(?<!\\)`/g) || []).length;
|
|
95
|
+
return (singleQuotes % 2 === 1) || (doubleQuotes % 2 === 1) || (backticks % 2 === 1);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Check if match should be ignored
|
|
99
|
+
*/
|
|
100
|
+
shouldIgnore(content, matchIndex) {
|
|
101
|
+
return this.isInComment(content, matchIndex) || this.isInString(content, matchIndex);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=base-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-detector.js","sourceRoot":"","sources":["../../../src/analyzers/security/base-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command Injection Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects potential command injection vulnerabilities
|
|
5
|
+
* OWASP A03:2021 - Injection
|
|
6
|
+
*/
|
|
7
|
+
import { BaseSecurityDetector } from '../base-detector.js';
|
|
8
|
+
import type { SecurityVulnerability } from '../types.js';
|
|
9
|
+
export declare class CommandInjectionDetector extends BaseSecurityDetector {
|
|
10
|
+
constructor();
|
|
11
|
+
scan(content: string, filePath: string): Promise<SecurityVulnerability[]>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command Injection Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects potential command injection vulnerabilities
|
|
5
|
+
* OWASP A03:2021 - Injection
|
|
6
|
+
*/
|
|
7
|
+
import { BaseSecurityDetector } from '../base-detector.js';
|
|
8
|
+
export class CommandInjectionDetector extends BaseSecurityDetector {
|
|
9
|
+
constructor() {
|
|
10
|
+
super({
|
|
11
|
+
id: 'command-injection',
|
|
12
|
+
name: 'Command Injection',
|
|
13
|
+
description: 'Detects potential command injection vulnerabilities',
|
|
14
|
+
severity: 'critical',
|
|
15
|
+
owaspCategory: 'A03:2021 - Injection',
|
|
16
|
+
cweId: 'CWE-78',
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async scan(content, filePath) {
|
|
20
|
+
if (!this.appliesTo(filePath)) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
const vulnerabilities = [];
|
|
24
|
+
// Pattern 1: exec/execSync with user input
|
|
25
|
+
const execPatterns = [
|
|
26
|
+
{
|
|
27
|
+
pattern: /(?:exec|execSync|spawn|spawnSync)\([^)]*(?:req\.|params\.|query\.|input|user)/gi,
|
|
28
|
+
method: 'child_process method',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
pattern: /(?:exec|execSync|spawn|spawnSync)\([`'][^`']*\$\{(?:req\.|params\.|query\.|input|user)/gi,
|
|
32
|
+
method: 'child_process method with template literal',
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
for (const { pattern, method } of execPatterns) {
|
|
36
|
+
let match;
|
|
37
|
+
const regex = new RegExp(pattern);
|
|
38
|
+
while ((match = regex.exec(content)) !== null) {
|
|
39
|
+
if (this.shouldIgnore(content, match.index)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const line = this.findLineNumber(content, match.index);
|
|
43
|
+
const code = this.extractCodeSnippet(content, match.index, 1);
|
|
44
|
+
vulnerabilities.push(this.createVulnerability(filePath, line, code, `${method} uses user input which may lead to command injection`, 'Never pass user input directly to shell commands. Use execFile with array arguments or validate/sanitize input strictly', [
|
|
45
|
+
'https://owasp.org/www-community/attacks/Command_Injection',
|
|
46
|
+
'https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html',
|
|
47
|
+
]));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Pattern 2: Shell: true option with user input
|
|
51
|
+
const shellTruePattern = /(?:exec|spawn)\([^,)]*,\s*\{[^}]*shell:\s*true[^}]*\}/gi;
|
|
52
|
+
let match;
|
|
53
|
+
while ((match = shellTruePattern.exec(content)) !== null) {
|
|
54
|
+
if (this.shouldIgnore(content, match.index)) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
// Check if user input is nearby
|
|
58
|
+
const contextStart = Math.max(0, match.index - 100);
|
|
59
|
+
const contextEnd = Math.min(content.length, match.index + 200);
|
|
60
|
+
const context = content.substring(contextStart, contextEnd);
|
|
61
|
+
if (/(?:req\.|params\.|query\.|input|user)/.test(context)) {
|
|
62
|
+
const line = this.findLineNumber(content, match.index);
|
|
63
|
+
const code = this.extractCodeSnippet(content, match.index, 1);
|
|
64
|
+
vulnerabilities.push(this.createVulnerability(filePath, line, code, 'Using shell: true with user input is extremely dangerous', 'Avoid shell: true. Use execFile or spawn with array arguments', [
|
|
65
|
+
'https://owasp.org/www-community/attacks/Command_Injection',
|
|
66
|
+
]));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Pattern 3: String concatenation in commands
|
|
70
|
+
const commandConcatPattern = /(?:exec|execSync)\(['"`][^'"`]*\+\s*(?:req\.|params\.|query\.|input|user)/gi;
|
|
71
|
+
while ((match = commandConcatPattern.exec(content)) !== null) {
|
|
72
|
+
if (this.shouldIgnore(content, match.index)) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const line = this.findLineNumber(content, match.index);
|
|
76
|
+
const code = this.extractCodeSnippet(content, match.index, 1);
|
|
77
|
+
vulnerabilities.push(this.createVulnerability(filePath, line, code, 'Command constructed using string concatenation with user input', 'Use execFile with array arguments to avoid command injection', [
|
|
78
|
+
'https://owasp.org/www-community/attacks/Command_Injection',
|
|
79
|
+
]));
|
|
80
|
+
}
|
|
81
|
+
return vulnerabilities;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=command-injection-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-injection-detector.js","sourceRoot":"","sources":["../../../../src/analyzers/security/detectors/command-injection-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hardcoded Secrets Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects hardcoded passwords, API keys, tokens, and other secrets
|
|
5
|
+
* OWASP A02:2021 - Cryptographic Failures
|
|
6
|
+
*/
|
|
7
|
+
import { BaseSecurityDetector } from '../base-detector.js';
|
|
8
|
+
import type { SecurityVulnerability } from '../types.js';
|
|
9
|
+
export declare class HardcodedSecretsDetector extends BaseSecurityDetector {
|
|
10
|
+
constructor();
|
|
11
|
+
scan(content: string, filePath: string): Promise<SecurityVulnerability[]>;
|
|
12
|
+
/**
|
|
13
|
+
* Check if value looks like a placeholder
|
|
14
|
+
*/
|
|
15
|
+
private isPlaceholder;
|
|
16
|
+
}
|