@maverick006/security-engine 1.0.2 → 1.0.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.
@@ -0,0 +1,16 @@
1
+ import { NormalizedFinding } from '@maverick006/types';
2
+ /**
3
+ * Options for finding deduplication.
4
+ */
5
+ export interface DeduplicationOptions {
6
+ lineTolerance?: number;
7
+ }
8
+ /**
9
+ * Deduplicates findings across multiple scanners:
10
+ * 1. Exact duplicates (same scanner, file, rule, line).
11
+ * 2. Cross-scanner duplicates (e.g. Trivy & npm-audit reporting the same CVE or package vuln).
12
+ * 3. Line shift tolerance (+/- 3 lines) to handle minor offset differences.
13
+ * 4. Preserves distinct vulnerabilities on the same file/line.
14
+ */
15
+ export declare function deduplicateFindings(findings: NormalizedFinding[], options?: DeduplicationOptions): NormalizedFinding[];
16
+ //# sourceMappingURL=deduplication.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deduplication.d.ts","sourceRoot":"","sources":["../src/deduplication.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAY,MAAM,oBAAoB,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAuDD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,OAAO,GAAE,oBAAyB,GACjC,iBAAiB,EAAE,CA6CrB"}
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deduplicateFindings = deduplicateFindings;
4
+ /**
5
+ * Normalizes a rule or CVE identifier to detect cross-scanner duplicates.
6
+ */
7
+ function normalizeIdentifier(finding) {
8
+ // If CVE or CWE is present, prioritize that as universal identifier
9
+ const cveMatch = (finding.ruleId || finding.title || finding.description || '').match(/CVE-\d{4}-\d+/i);
10
+ if (cveMatch) {
11
+ return cveMatch[0].toUpperCase();
12
+ }
13
+ // If package-based vulnerability, match package + cwe/rule
14
+ if (finding.package) {
15
+ const pkg = finding.package.toLowerCase();
16
+ const cwe = finding.cwe ? finding.cwe.toLowerCase() : '';
17
+ return `pkg:${pkg}:${cwe || finding.ruleId || 'vuln'}`;
18
+ }
19
+ // Generic rule ID fallback
20
+ return (finding.ruleId || finding.title || 'unknown').toLowerCase().trim();
21
+ }
22
+ /**
23
+ * Normalizes file paths for reliable cross-platform comparison.
24
+ */
25
+ function normalizeFilePath(filePath) {
26
+ if (!filePath)
27
+ return '';
28
+ return filePath.replace(/\\/g, '/').toLowerCase().trim();
29
+ }
30
+ /**
31
+ * Merges two findings for the same vulnerability, retaining the highest confidence and most complete metadata.
32
+ */
33
+ function mergeFindings(primary, secondary) {
34
+ return {
35
+ ...primary,
36
+ // Keep the more severe or primary severity
37
+ severity: primary.severity || secondary.severity,
38
+ confidence: primary.confidence || secondary.confidence,
39
+ cwe: primary.cwe || secondary.cwe,
40
+ owasp: primary.owasp || secondary.owasp,
41
+ remediation: primary.remediation || secondary.remediation,
42
+ codeSnippet: primary.codeSnippet || secondary.codeSnippet,
43
+ package: primary.package || secondary.package,
44
+ packageVersion: primary.packageVersion || secondary.packageVersion,
45
+ fixedVersion: primary.fixedVersion || secondary.fixedVersion,
46
+ references: Array.from(new Set([...(primary.references || []), ...(secondary.references || [])])),
47
+ // Note in scanner if multiple scanners detected it
48
+ scanner: primary.scanner.includes(secondary.scanner)
49
+ ? primary.scanner
50
+ : `${primary.scanner}, ${secondary.scanner}`
51
+ };
52
+ }
53
+ /**
54
+ * Deduplicates findings across multiple scanners:
55
+ * 1. Exact duplicates (same scanner, file, rule, line).
56
+ * 2. Cross-scanner duplicates (e.g. Trivy & npm-audit reporting the same CVE or package vuln).
57
+ * 3. Line shift tolerance (+/- 3 lines) to handle minor offset differences.
58
+ * 4. Preserves distinct vulnerabilities on the same file/line.
59
+ */
60
+ function deduplicateFindings(findings, options = {}) {
61
+ const lineTolerance = options.lineTolerance ?? 3;
62
+ const deduplicated = [];
63
+ for (const candidate of findings) {
64
+ const candidateFile = normalizeFilePath(candidate.file);
65
+ const candidateId = normalizeIdentifier(candidate);
66
+ const candidateLine = candidate.line || 0;
67
+ let matchedIndex = -1;
68
+ for (let i = 0; i < deduplicated.length; i++) {
69
+ const existing = deduplicated[i];
70
+ const existingFile = normalizeFilePath(existing.file);
71
+ const existingId = normalizeIdentifier(existing);
72
+ const existingLine = existing.line || 0;
73
+ // Check for same file & same vulnerability identity
74
+ const isSameFile = candidateFile && existingFile ? candidateFile === existingFile : true;
75
+ const isSameVuln = candidateId === existingId;
76
+ if (isSameFile && isSameVuln) {
77
+ // If line numbers exist, check line tolerance
78
+ if (candidateLine > 0 && existingLine > 0) {
79
+ if (Math.abs(candidateLine - existingLine) <= lineTolerance) {
80
+ matchedIndex = i;
81
+ break;
82
+ }
83
+ }
84
+ else {
85
+ // If either lacks line numbers (e.g. package/repo level), treat as match
86
+ matchedIndex = i;
87
+ break;
88
+ }
89
+ }
90
+ }
91
+ if (matchedIndex >= 0) {
92
+ // Merge with existing finding
93
+ deduplicated[matchedIndex] = mergeFindings(deduplicated[matchedIndex], candidate);
94
+ }
95
+ else {
96
+ deduplicated.push({ ...candidate });
97
+ }
98
+ }
99
+ return deduplicated;
100
+ }
101
+ //# sourceMappingURL=deduplication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deduplication.js","sourceRoot":"","sources":["../src/deduplication.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './scanner';
2
2
  export * from './orchestrator';
3
3
  export * from './scoring';
4
+ export * from './deduplication';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -17,4 +17,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./scanner"), exports);
18
18
  __exportStar(require("./orchestrator"), exports);
19
19
  __exportStar(require("./scoring"), exports);
20
+ __exportStar(require("./deduplication"), exports);
20
21
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,iDAA+B;AAC/B,4CAA0B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,iDAA+B;AAC/B,4CAA0B;AAC1B,kDAAgC"}
@@ -1,18 +1,23 @@
1
- import { ScanInput, ScannerResult } from '@maverick006/types';
1
+ import { ScanInput, ScannerResult, ScannerCoverage } from '@maverick006/types';
2
2
  import { SecurityScanner } from './scanner';
3
+ export interface OrchestratorOptions {
4
+ concurrencyLimit?: number;
5
+ timeoutMs?: number;
6
+ }
7
+ export interface OrchestratedScanResult extends ScannerResult {
8
+ scannerResults: ScannerResult[];
9
+ coverage: ScannerCoverage;
10
+ }
3
11
  /**
4
12
  * Orchestrates the execution of multiple security scanners and aggregates/deduplicates their findings.
5
13
  */
6
14
  export declare class Orchestrator {
7
15
  private scanners;
8
- constructor(scanners: SecurityScanner[]);
9
- /**
10
- * Executes all registered scanners against the given input.
11
- */
12
- runScan(input: ScanInput): Promise<ScannerResult>;
16
+ private options;
17
+ constructor(scanners: SecurityScanner[], options?: OrchestratorOptions);
13
18
  /**
14
- * Deduplicates findings based on a fingerprint generated from ruleId, file, line, and column.
19
+ * Executes registered scanners using a bounded concurrency pool.
15
20
  */
16
- private deduplicateFindings;
21
+ runScan(input: ScanInput): Promise<OrchestratedScanResult>;
17
22
  }
18
23
  //# sourceMappingURL=orchestrator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,SAAS,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAyB;gBAE7B,QAAQ,EAAE,eAAe,EAAE;IAIvC;;OAEG;IACG,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC;IAsCvD;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAiB5B"}
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,SAAS,EAAE,aAAa,EAAgB,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAChH,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAG5C,MAAM,WAAW,mBAAmB;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC3D,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,QAAQ,EAAE,eAAe,CAAC;CAC3B;AA+CD;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,OAAO,CAAsB;gBAEzB,QAAQ,EAAE,eAAe,EAAE,EAAE,OAAO,GAAE,mBAAwB;IAQ1E;;OAEG;IACG,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,sBAAsB,CAAC;CAsIjE"}
@@ -1,67 +1,182 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Orchestrator = void 0;
4
+ const types_1 = require("@maverick006/types");
5
+ const deduplication_1 = require("./deduplication");
6
+ /**
7
+ * Runs tasks with a bounded concurrency pool (no unlimited Promise.all).
8
+ */
9
+ async function runWithConcurrencyLimit(items, limit, fn) {
10
+ const results = new Array(items.length);
11
+ let currentIndex = 0;
12
+ const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {
13
+ while (currentIndex < items.length) {
14
+ const index = currentIndex++;
15
+ results[index] = await fn(items[index]);
16
+ }
17
+ });
18
+ await Promise.all(workers);
19
+ return results;
20
+ }
21
+ /**
22
+ * Wraps a promise with a timeout.
23
+ */
24
+ function withTimeout(promise, timeoutMs, scannerName) {
25
+ return new Promise((resolve, reject) => {
26
+ const timer = setTimeout(() => {
27
+ const err = new Error(`Scanner ${scannerName} timed out after ${timeoutMs}ms`);
28
+ err.code = 'ETIMEDOUT';
29
+ reject(err);
30
+ }, timeoutMs);
31
+ promise
32
+ .then(val => {
33
+ clearTimeout(timer);
34
+ resolve(val);
35
+ })
36
+ .catch(err => {
37
+ clearTimeout(timer);
38
+ reject(err);
39
+ });
40
+ });
41
+ }
4
42
  /**
5
43
  * Orchestrates the execution of multiple security scanners and aggregates/deduplicates their findings.
6
44
  */
7
45
  class Orchestrator {
8
46
  scanners = [];
9
- constructor(scanners) {
47
+ options;
48
+ constructor(scanners, options = {}) {
10
49
  this.scanners = scanners;
50
+ this.options = {
51
+ concurrencyLimit: options.concurrencyLimit ?? 3,
52
+ timeoutMs: options.timeoutMs ?? 120_000
53
+ };
11
54
  }
12
55
  /**
13
- * Executes all registered scanners against the given input.
56
+ * Executes registered scanners using a bounded concurrency pool.
14
57
  */
15
58
  async runScan(input) {
16
59
  const startTime = new Date();
17
- // Execute all scanners concurrently
18
- const scanPromises = this.scanners.map(scanner => scanner.scan(input));
19
- const results = await Promise.allSettled(scanPromises);
60
+ const concurrency = this.options.concurrencyLimit ?? 3;
61
+ const timeout = this.options.timeoutMs ?? 120_000;
62
+ const executeScanner = async (scanner) => {
63
+ const scanStart = new Date();
64
+ // Check applicability if scanner provides capability detection
65
+ if (scanner.capabilities?.detectApplicability) {
66
+ try {
67
+ const isApplicable = await scanner.capabilities.detectApplicability(input.repositoryPath, input);
68
+ if (!isApplicable) {
69
+ const scanEnd = new Date();
70
+ return {
71
+ scanner: scanner.name,
72
+ success: true,
73
+ state: types_1.ScannerState.SKIPPED,
74
+ reason: `Skipped: Not applicable to repository or target`,
75
+ findings: [],
76
+ startTime: scanStart,
77
+ endTime: scanEnd,
78
+ durationMs: scanEnd.getTime() - scanStart.getTime()
79
+ };
80
+ }
81
+ }
82
+ catch (err) {
83
+ console.warn(`Applicability check error for ${scanner.name}:`, err.message);
84
+ }
85
+ }
86
+ try {
87
+ const scanPromise = scanner.scan(input);
88
+ const result = await withTimeout(scanPromise, timeout, scanner.name);
89
+ const scanEnd = new Date();
90
+ return {
91
+ ...result,
92
+ state: result.state || (result.success ? types_1.ScannerState.SUCCESS : types_1.ScannerState.FAILED),
93
+ durationMs: scanEnd.getTime() - scanStart.getTime(),
94
+ endTime: scanEnd
95
+ };
96
+ }
97
+ catch (err) {
98
+ const scanEnd = new Date();
99
+ const durationMs = scanEnd.getTime() - scanStart.getTime();
100
+ if (err.code === 'ETIMEDOUT') {
101
+ return {
102
+ scanner: scanner.name,
103
+ success: false,
104
+ state: types_1.ScannerState.TIMEOUT,
105
+ error: err.message,
106
+ reason: `Execution exceeded timeout of ${timeout}ms`,
107
+ findings: [],
108
+ startTime: scanStart,
109
+ endTime: scanEnd,
110
+ durationMs
111
+ };
112
+ }
113
+ if (err.code === 'ENOENT') {
114
+ return {
115
+ scanner: scanner.name,
116
+ success: false,
117
+ state: types_1.ScannerState.NOT_INSTALLED,
118
+ error: err.message,
119
+ reason: `Scanner executable was not found on PATH`,
120
+ findings: [],
121
+ startTime: scanStart,
122
+ endTime: scanEnd,
123
+ durationMs
124
+ };
125
+ }
126
+ return {
127
+ scanner: scanner.name,
128
+ success: false,
129
+ state: types_1.ScannerState.FAILED,
130
+ error: err.message || String(err),
131
+ findings: [],
132
+ startTime: scanStart,
133
+ endTime: scanEnd,
134
+ durationMs
135
+ };
136
+ }
137
+ };
138
+ // Execute through bounded concurrency worker pool
139
+ const scannerResults = await runWithConcurrencyLimit(this.scanners, concurrency, executeScanner);
20
140
  let allFindings = [];
21
141
  const rawOutputs = {};
22
- for (let i = 0; i < results.length; i++) {
23
- const result = results[i];
24
- const scannerName = this.scanners[i].name;
25
- if (result.status === 'fulfilled') {
26
- const data = result.value;
142
+ for (const data of scannerResults) {
143
+ if (data.findings && data.findings.length > 0) {
27
144
  allFindings = allFindings.concat(data.findings);
28
- if (data.rawOutput) {
29
- rawOutputs[scannerName] = data.rawOutput;
30
- }
31
145
  }
32
- else {
33
- // Log scanner failure safely (in production this would use a proper logger)
34
- console.error(`Scanner ${scannerName} failed:`, result.reason);
146
+ if (data.rawOutput) {
147
+ rawOutputs[data.scanner] = data.rawOutput;
35
148
  }
36
149
  }
37
- const deduplicatedFindings = this.deduplicateFindings(allFindings);
150
+ // High-precision deduplication across scanners with line tolerance
151
+ const deduplicatedFindings = (0, deduplication_1.deduplicateFindings)(allFindings);
152
+ // Standardize finding IDs to VG-FIND-001, VG-FIND-002, etc.
153
+ deduplicatedFindings.forEach((finding, index) => {
154
+ finding.id = `VG-FIND-${String(index + 1).padStart(3, '0')}`;
155
+ });
156
+ // Compute coverage matrix based on successful scanner executions
157
+ const coverage = {
158
+ code: scannerResults.some(r => r.scanner.toLowerCase().includes('semgrep') && r.state === types_1.ScannerState.SUCCESS),
159
+ dependencies: scannerResults.some(r => (r.scanner.toLowerCase().includes('npm') || r.scanner.toLowerCase().includes('audit') || r.scanner.toLowerCase().includes('trivy')) && r.state === types_1.ScannerState.SUCCESS),
160
+ secrets: scannerResults.some(r => r.scanner.toLowerCase().includes('gitleaks') && r.state === types_1.ScannerState.SUCCESS),
161
+ containers: scannerResults.some(r => r.scanner.toLowerCase().includes('trivy') && r.state === types_1.ScannerState.SUCCESS),
162
+ iac: scannerResults.some(r => r.scanner.toLowerCase().includes('checkov') && r.state === types_1.ScannerState.SUCCESS),
163
+ web: scannerResults.some(r => r.scanner.toLowerCase().includes('zap') && r.state === types_1.ScannerState.SUCCESS),
164
+ cloud: scannerResults.some(r => (r.scanner.toLowerCase().includes('prowler') || r.scanner.toLowerCase().includes('cspm')) && r.state === types_1.ScannerState.SUCCESS)
165
+ };
166
+ const endTime = new Date();
38
167
  return {
39
168
  scanner: 'VibeGuard_Orchestrator',
40
- success: true,
169
+ success: scannerResults.some(r => r.state === types_1.ScannerState.SUCCESS),
170
+ state: types_1.ScannerState.SUCCESS,
171
+ durationMs: endTime.getTime() - startTime.getTime(),
41
172
  findings: deduplicatedFindings,
42
- rawOutput: JSON.stringify(rawOutputs), // Aggregate raw outputs
173
+ scannerResults,
174
+ coverage,
175
+ rawOutput: JSON.stringify(rawOutputs),
43
176
  startTime,
44
- endTime: new Date()
177
+ endTime
45
178
  };
46
179
  }
47
- /**
48
- * Deduplicates findings based on a fingerprint generated from ruleId, file, line, and column.
49
- */
50
- deduplicateFindings(findings) {
51
- const unique = new Map();
52
- for (const finding of findings) {
53
- // Create a unique fingerprint for the finding
54
- const fingerprint = `${finding.ruleId}-${finding.file}-${finding.line}-${finding.column}`;
55
- if (!unique.has(fingerprint)) {
56
- unique.set(fingerprint, finding);
57
- }
58
- else {
59
- // If it already exists, we might want to merge information, but for now we keep the first one
60
- // Optionally, if the new one has higher confidence, we could replace it.
61
- }
62
- }
63
- return Array.from(unique.values());
64
- }
65
180
  }
66
181
  exports.Orchestrator = Orchestrator;
67
182
  //# sourceMappingURL=orchestrator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":";;;AAGA;;GAEG;AACH,MAAa,YAAY;IACf,QAAQ,GAAsB,EAAE,CAAC;IAEzC,YAAY,QAA2B;QACrC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,KAAgB;QAC5B,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAE7B,oCAAoC;QACpC,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACvE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QAEvD,IAAI,WAAW,GAAwB,EAAE,CAAC;QAC1C,MAAM,UAAU,GAA2B,EAAE,CAAC;QAE9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAC1B,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAE1C,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;gBAClC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC1B,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAChD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;oBACnB,UAAU,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;gBAC3C,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,4EAA4E;gBAC5E,OAAO,CAAC,KAAK,CAAC,WAAW,WAAW,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YACjE,CAAC;QACH,CAAC;QAED,MAAM,oBAAoB,GAAG,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAEnE,OAAO;YACL,OAAO,EAAE,wBAAwB;YACjC,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,oBAAoB;YAC9B,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,wBAAwB;YAC/D,SAAS;YACT,OAAO,EAAE,IAAI,IAAI,EAAE;SACpB,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,mBAAmB,CAAC,QAA6B;QACvD,MAAM,MAAM,GAAG,IAAI,GAAG,EAA6B,CAAC;QAEpD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,8CAA8C;YAC9C,MAAM,WAAW,GAAG,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YAE1F,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC7B,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YACnC,CAAC;iBAAM,CAAC;gBACN,8FAA8F;gBAC9F,yEAAyE;YAC3E,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IACrC,CAAC;CACF;AApED,oCAoEC"}
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"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"}
package/dist/scanner.d.ts CHANGED
@@ -1,4 +1,9 @@
1
1
  import { ScanInput, ScannerResult } from '@maverick006/types';
2
+ export interface ScannerCapability {
3
+ category: 'code' | 'dependencies' | 'secrets' | 'containers' | 'iac' | 'web' | 'cloud';
4
+ requiresCredentials?: boolean;
5
+ detectApplicability?: (repoPath: string, input?: ScanInput) => Promise<boolean> | boolean;
6
+ }
2
7
  /**
3
8
  * Base interface that all VibeGuard scanners must implement.
4
9
  * This provides the core abstraction allowing new scanners to be added
@@ -13,6 +18,10 @@ export interface SecurityScanner {
13
18
  * The version of the scanner, if known/applicable.
14
19
  */
15
20
  version?: string;
21
+ /**
22
+ * Optional capability metadata and applicability detection.
23
+ */
24
+ capabilities?: ScannerCapability;
16
25
  /**
17
26
  * Executes the scanner against the given input.
18
27
  *
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE9D;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CAChD"}
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,GAAG,YAAY,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,CAAC;IACvF,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,mBAAmB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAC3F;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,YAAY,CAAC,EAAE,iBAAiB,CAAC;IAEjC;;;;;OAKG;IACH,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CAChD"}
package/dist/scoring.d.ts CHANGED
@@ -1,7 +1,5 @@
1
- import { NormalizedFinding } from '@maverick006/types';
2
- export interface ScoreResult {
3
- score: number;
4
- grade: 'A' | 'B' | 'C' | 'D' | 'F';
1
+ import { NormalizedFinding, ScannerCoverage, DeterministicScore } from '@maverick006/types';
2
+ export interface ScoreResult extends DeterministicScore {
5
3
  metrics: {
6
4
  critical: number;
7
5
  high: number;
@@ -10,15 +8,23 @@ export interface ScoreResult {
10
8
  };
11
9
  }
12
10
  /**
13
- * Calculates a deterministic security score and grade based on the volume and severity of findings.
14
- * Weights: CRITICAL=100, HIGH=20, MEDIUM=5, LOW=1
11
+ * Calculates a deterministic, reproducible security score (0 to 100) and grade
12
+ * based on the volume and severity of unique findings.
15
13
  *
16
- * Grade thresholds:
17
- * A: <= 10 (e.g., up to 2 mediums, or 10 lows)
18
- * B: <= 30 (e.g., 1 high, or several mediums)
19
- * C: <= 70 (e.g., 3 highs)
20
- * D: <= 150 (e.g., many highs, but no criticals. Or 1 critical and nothing else = 100, wait, 1 critical is auto F)
21
- * F: > 150 OR any CRITICAL finding.
14
+ * Rules:
15
+ * - Base score: 100
16
+ * - Critical: -30 points per finding (any critical forces Grade F and caps score at <= 49)
17
+ * - High: -10 points per finding
18
+ * - Medium: -3 points per finding
19
+ * - Low: -1 point per finding
20
+ * - Info: 0 points
21
+ *
22
+ * Grades:
23
+ * A: 90 - 100
24
+ * B: 80 - 89
25
+ * C: 70 - 79
26
+ * D: 50 - 69
27
+ * F: < 50 OR any CRITICAL finding
22
28
  */
23
- export declare function calculateScore(findings: NormalizedFinding[]): ScoreResult;
29
+ export declare function calculateScore(findings: NormalizedFinding[], coverage?: Partial<ScannerCoverage>): ScoreResult;
24
30
  //# sourceMappingURL=scoring.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../src/scoring.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAY,MAAM,oBAAoB,CAAC;AAEjE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IACnC,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;CACH;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,WAAW,CAsDzE"}
1
+ {"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../src/scoring.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAY,eAAe,EAAE,kBAAkB,EAAmB,MAAM,oBAAoB,CAAC;AAEvH,MAAM,WAAW,WAAY,SAAQ,kBAAkB;IACrD,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAClC,WAAW,CA0Hb"}