api-tests-coverage 1.0.23 → 1.0.24

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.
Files changed (131) hide show
  1. package/README.md +39 -0
  2. package/config.yaml.example +35 -0
  3. package/dist/dashboard/dist/assets/_basePickBy-D4Hl8chy.js +1 -0
  4. package/dist/dashboard/dist/assets/_baseUniq-BSUUnV_V.js +1 -0
  5. package/dist/dashboard/dist/assets/arc-DhDluTY5.js +1 -0
  6. package/dist/dashboard/dist/assets/architectureDiagram-VXUJARFQ-DGlUU7dC.js +36 -0
  7. package/dist/dashboard/dist/assets/blockDiagram-VD42YOAC-CgXi3kEZ.js +122 -0
  8. package/dist/dashboard/dist/assets/c4Diagram-YG6GDRKO-Cr3xB15y.js +10 -0
  9. package/dist/dashboard/dist/assets/channel-DYAie-7m.js +1 -0
  10. package/dist/dashboard/dist/assets/chunk-4BX2VUAB-BaW3__pI.js +1 -0
  11. package/dist/dashboard/dist/assets/chunk-55IACEB6-DyYevfEQ.js +1 -0
  12. package/dist/dashboard/dist/assets/chunk-B4BG7PRW-C2bwZFec.js +165 -0
  13. package/dist/dashboard/dist/assets/chunk-DI55MBZ5-DO0T2xne.js +220 -0
  14. package/dist/dashboard/dist/assets/chunk-FMBD7UC4-CCYA4j_f.js +15 -0
  15. package/dist/dashboard/dist/assets/chunk-QN33PNHL-Cdhqs7xo.js +1 -0
  16. package/dist/dashboard/dist/assets/chunk-QZHKN3VN-BzHw38Ki.js +1 -0
  17. package/dist/dashboard/dist/assets/chunk-TZMSLE5B-dkJ0rsgF.js +1 -0
  18. package/dist/dashboard/dist/assets/classDiagram-2ON5EDUG-DiIv5Pho.js +1 -0
  19. package/dist/dashboard/dist/assets/classDiagram-v2-WZHVMYZB-DiIv5Pho.js +1 -0
  20. package/dist/dashboard/dist/assets/clone-B4LorrSy.js +1 -0
  21. package/dist/dashboard/dist/assets/cose-bilkent-S5V4N54A-jzGbyPIS.js +1 -0
  22. package/dist/dashboard/dist/assets/dagre-6UL2VRFP-D7rgvBx1.js +4 -0
  23. package/dist/dashboard/dist/assets/diagram-PSM6KHXK-2rYklqon.js +24 -0
  24. package/dist/dashboard/dist/assets/diagram-QEK2KX5R-CGrvALqm.js +43 -0
  25. package/dist/dashboard/dist/assets/diagram-S2PKOQOG-DA3c-QP4.js +24 -0
  26. package/dist/dashboard/dist/assets/erDiagram-Q2GNP2WA-BsYH8cLH.js +60 -0
  27. package/dist/dashboard/dist/assets/flowDiagram-NV44I4VS-Da_JhBCy.js +162 -0
  28. package/dist/dashboard/dist/assets/ganttDiagram-JELNMOA3-D8FTswNn.js +267 -0
  29. package/dist/dashboard/dist/assets/gitGraphDiagram-V2S2FVAM-BFJR-ITH.js +65 -0
  30. package/dist/dashboard/dist/assets/graph-CIvnjOQQ.js +1 -0
  31. package/dist/dashboard/dist/assets/index-BWX0sSZn.css +1 -0
  32. package/dist/dashboard/dist/assets/index-CbAFWEor.js +777 -0
  33. package/dist/dashboard/dist/assets/infoDiagram-HS3SLOUP-OcK0Lxgi.js +2 -0
  34. package/dist/dashboard/dist/assets/journeyDiagram-XKPGCS4Q-DTJukVOY.js +139 -0
  35. package/dist/dashboard/dist/assets/kanban-definition-3W4ZIXB7-Di65fNuD.js +89 -0
  36. package/dist/dashboard/dist/assets/layout-DAt24RVX.js +1 -0
  37. package/dist/dashboard/dist/assets/mindmap-definition-VGOIOE7T-DxI8MXCF.js +68 -0
  38. package/dist/dashboard/dist/assets/pieDiagram-ADFJNKIX-BafKx3_Y.js +30 -0
  39. package/dist/dashboard/dist/assets/quadrantDiagram-AYHSOK5B-BcZsArkk.js +7 -0
  40. package/dist/dashboard/dist/assets/requirementDiagram-UZGBJVZJ-CqFAO2t6.js +64 -0
  41. package/dist/dashboard/dist/assets/sankeyDiagram-TZEHDZUN-CqSaCg-3.js +10 -0
  42. package/dist/dashboard/dist/assets/sequenceDiagram-WL72ISMW-6IXD1uqW.js +145 -0
  43. package/dist/dashboard/dist/assets/stateDiagram-FKZM4ZOC-DvSVQAfp.js +1 -0
  44. package/dist/dashboard/dist/assets/stateDiagram-v2-4FDKWEC3-BMFdt0QQ.js +1 -0
  45. package/dist/dashboard/dist/assets/timeline-definition-IT6M3QCI-Cll7Nvth.js +61 -0
  46. package/dist/dashboard/dist/assets/treemap-GDKQZRPO-DtqX8zNC.js +162 -0
  47. package/dist/dashboard/dist/assets/xychartDiagram-PRI3JC2R-zxwS9i0A.js +7 -0
  48. package/dist/dashboard/dist/index.html +2 -2
  49. package/dist/dashboard/dist/reports/coverage-summary.json +75 -1
  50. package/dist/dashboard/dist/reports/security-full.json +157 -0
  51. package/dist/src/compatibilityCoverage.d.ts +34 -15
  52. package/dist/src/compatibilityCoverage.d.ts.map +1 -1
  53. package/dist/src/compatibilityCoverage.js +387 -85
  54. package/dist/src/config/defaultConfig.d.ts.map +1 -1
  55. package/dist/src/config/defaultConfig.js +62 -0
  56. package/dist/src/config/schema.d.ts.map +1 -1
  57. package/dist/src/config/schema.js +1 -1
  58. package/dist/src/config/types.d.ts +81 -1
  59. package/dist/src/config/types.d.ts.map +1 -1
  60. package/dist/src/config/validateConfig.d.ts.map +1 -1
  61. package/dist/src/config/validateConfig.js +126 -0
  62. package/dist/src/contracts/compatibilityMatrix.d.ts +20 -0
  63. package/dist/src/contracts/compatibilityMatrix.d.ts.map +1 -0
  64. package/dist/src/contracts/compatibilityMatrix.js +198 -0
  65. package/dist/src/contracts/pactBrokerClient.d.ts +10 -0
  66. package/dist/src/contracts/pactBrokerClient.d.ts.map +1 -0
  67. package/dist/src/contracts/pactBrokerClient.js +117 -0
  68. package/dist/src/contracts/schemaEvolutionChecker.d.ts +17 -0
  69. package/dist/src/contracts/schemaEvolutionChecker.d.ts.map +1 -0
  70. package/dist/src/contracts/schemaEvolutionChecker.js +95 -0
  71. package/dist/src/contracts/springCloudContractParser.d.ts +10 -0
  72. package/dist/src/contracts/springCloudContractParser.d.ts.map +1 -0
  73. package/dist/src/contracts/springCloudContractParser.js +144 -0
  74. package/dist/src/discovery/fileClassifier.d.ts.map +1 -1
  75. package/dist/src/discovery/fileClassifier.js +25 -0
  76. package/dist/src/discovery/projectDiscovery.d.ts +2 -0
  77. package/dist/src/discovery/projectDiscovery.d.ts.map +1 -1
  78. package/dist/src/discovery/projectDiscovery.js +25 -25
  79. package/dist/src/index.js +233 -16
  80. package/dist/src/inference/routeInference.d.ts +10 -2
  81. package/dist/src/inference/routeInference.d.ts.map +1 -1
  82. package/dist/src/inference/routeInference.js +363 -62
  83. package/dist/src/languageDetection.d.ts.map +1 -1
  84. package/dist/src/languageDetection.js +21 -4
  85. package/dist/src/lib/index.d.ts +3 -0
  86. package/dist/src/lib/index.d.ts.map +1 -1
  87. package/dist/src/lib/index.js +3 -1
  88. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.js +152 -79
  89. package/dist/src/pipeline/stages/tia/testEndpointMapper.d.ts +5 -1
  90. package/dist/src/pipeline/stages/tia/testEndpointMapper.d.ts.map +1 -1
  91. package/dist/src/pipeline/stages/tia/testEndpointMapper.js +356 -42
  92. package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts.map +1 -1
  93. package/dist/src/pipeline/stages/tia/testLayerClassifier.js +20 -5
  94. package/dist/src/pipeline/stages/tia/tiaStage.d.ts.map +1 -1
  95. package/dist/src/pipeline/stages/tia/tiaStage.js +3 -1
  96. package/dist/src/pipeline/stages/tia/types.d.ts +11 -2
  97. package/dist/src/pipeline/stages/tia/types.d.ts.map +1 -1
  98. package/dist/src/projectDefaults.d.ts +6 -0
  99. package/dist/src/projectDefaults.d.ts.map +1 -0
  100. package/dist/src/projectDefaults.js +43 -0
  101. package/dist/src/security/hub.d.ts +81 -0
  102. package/dist/src/security/hub.d.ts.map +1 -0
  103. package/dist/src/security/hub.js +420 -0
  104. package/dist/src/security/index.d.ts +1 -0
  105. package/dist/src/security/index.d.ts.map +1 -1
  106. package/dist/src/security/index.js +8 -2
  107. package/dist/src/security/normalizers/gitleaks.d.ts +7 -0
  108. package/dist/src/security/normalizers/gitleaks.d.ts.map +1 -0
  109. package/dist/src/security/normalizers/gitleaks.js +32 -0
  110. package/dist/src/security/scanners/gitleaks.d.ts +3 -0
  111. package/dist/src/security/scanners/gitleaks.d.ts.map +1 -0
  112. package/dist/src/security/scanners/gitleaks.js +105 -0
  113. package/dist/src/security/scanners/semgrep.d.ts.map +1 -1
  114. package/dist/src/security/scanners/semgrep.js +24 -2
  115. package/dist/src/security/scanners/trivy.d.ts.map +1 -1
  116. package/dist/src/security/scanners/trivy.js +24 -2
  117. package/dist/src/security/scanners/zap.d.ts.map +1 -1
  118. package/dist/src/security/scanners/zap.js +27 -2
  119. package/dist/src/security/types.d.ts +15 -1
  120. package/dist/src/security/types.d.ts.map +1 -1
  121. package/dist/src/streaming/schema/index.d.ts +23 -0
  122. package/dist/src/streaming/schema/index.d.ts.map +1 -0
  123. package/dist/src/streaming/schema/index.js +196 -0
  124. package/dist/src/summary/markdownRenderer.d.ts.map +1 -1
  125. package/dist/src/summary/markdownRenderer.js +15 -1
  126. package/dist/src/summary/summaryTypes.d.ts.map +1 -1
  127. package/dist/src/summary/summaryTypes.js +1 -0
  128. package/dist/src/unitAnalysis.d.ts +145 -0
  129. package/dist/src/unitAnalysis.d.ts.map +1 -0
  130. package/dist/src/unitAnalysis.js +1392 -0
  131. package/package.json +1 -1
@@ -0,0 +1,81 @@
1
+ import type { AnalyzerConfig } from '../config/types';
2
+ import type { SecurityControlCoverage, SecurityCoverageReport } from '../securityCoverage';
3
+ import { FindingSeverity, ScannerName, SecurityFinding } from './types';
4
+ type OwnFinding = {
5
+ severity: FindingSeverity;
6
+ title: string;
7
+ filePath: string;
8
+ lineStart?: number;
9
+ pattern: string;
10
+ };
11
+ type SecurityToolSection = {
12
+ source: ScannerName | null;
13
+ toolName: string;
14
+ version?: string;
15
+ generatedAt?: string;
16
+ reportFile?: string;
17
+ fullReportLink?: string;
18
+ reason?: string;
19
+ severityBreakdown: Record<FindingSeverity, number>;
20
+ topFindings: SecurityFinding[];
21
+ };
22
+ export interface SecurityFullReport {
23
+ generatedAt: string;
24
+ authCoverage: {
25
+ source: 'own-scanner';
26
+ oauth2Detected: boolean;
27
+ jwtDetected: boolean;
28
+ endpointsWithAuth: number;
29
+ endpointsTotal: number;
30
+ endpointsMissingAuth: string[];
31
+ testedAuthFlows: number;
32
+ };
33
+ ownScanFindings: {
34
+ source: 'own-scanner';
35
+ hardcodedSecrets: OwnFinding[];
36
+ injectionRisks: OwnFinding[];
37
+ kafkaSecurityIssues: OwnFinding[];
38
+ insecurePatterns: OwnFinding[];
39
+ };
40
+ dependencyScan: SecurityToolSection & {
41
+ vulnerabilities: SecurityFinding[];
42
+ };
43
+ sastScan: SecurityToolSection & {
44
+ findings: SecurityFinding[];
45
+ };
46
+ secretScan: SecurityToolSection & {
47
+ secrets: SecurityFinding[];
48
+ };
49
+ dastScan: SecurityToolSection & {
50
+ findings: SecurityFinding[];
51
+ };
52
+ riskSummary: {
53
+ overallRisk: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
54
+ criticalItems: Array<{
55
+ source: string;
56
+ severity: FindingSeverity;
57
+ title: string;
58
+ file?: string;
59
+ line?: number;
60
+ }>;
61
+ recommendations: string[];
62
+ };
63
+ }
64
+ export interface SecurityHubOptions {
65
+ specPath: string;
66
+ testsGlob: string;
67
+ sourceGlob?: string;
68
+ reportsDir: string;
69
+ coverageReport: SecurityCoverageReport;
70
+ coverages: SecurityControlCoverage[];
71
+ config: AnalyzerConfig;
72
+ semgrepReport?: string;
73
+ trivyReport?: string;
74
+ gitleaksReport?: string;
75
+ zapReport?: string;
76
+ workspace?: string;
77
+ }
78
+ export declare function generateSecurityFullReport(options: SecurityHubOptions): Promise<SecurityFullReport>;
79
+ export declare function writeSecurityFullReport(report: SecurityFullReport, reportsDir: string): string;
80
+ export {};
81
+ //# sourceMappingURL=hub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hub.d.ts","sourceRoot":"","sources":["../../../src/security/hub.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,420 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.generateSecurityFullReport = generateSecurityFullReport;
40
+ exports.writeSecurityFullReport = writeSecurityFullReport;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const child_process_1 = require("child_process");
44
+ const fast_glob_1 = __importDefault(require("fast-glob"));
45
+ const swagger_parser_1 = __importDefault(require("@apidevtools/swagger-parser"));
46
+ const semgrep_1 = require("./scanners/semgrep");
47
+ const trivy_1 = require("./scanners/trivy");
48
+ const zap_1 = require("./scanners/zap");
49
+ const gitleaks_1 = require("./scanners/gitleaks");
50
+ const ZERO_COUNTS = {
51
+ CRITICAL: 0,
52
+ HIGH: 0,
53
+ MEDIUM: 0,
54
+ LOW: 0,
55
+ };
56
+ const CONFIGURE_COMMANDS = {
57
+ semgrep: 'semgrep scan --json --config p/security-audit > reports/semgrep.json',
58
+ trivy: 'trivy fs --format json --output reports/trivy.json .',
59
+ gitleaks: 'gitleaks detect --report-format json > reports/gitleaks.json',
60
+ zap: 'zap-baseline.py -J reports/zap.json -t https://your-service.example.com',
61
+ other: '',
62
+ };
63
+ const SCANNER_ENABLEMENT_HELP = {
64
+ trivy: 'dependency scanning',
65
+ semgrep: 'SAST scanning',
66
+ gitleaks: 'secret scanning',
67
+ zap: 'DAST scanning',
68
+ };
69
+ // Keep the generic string threshold low enough to catch obvious hardcoded
70
+ // tokens, but high enough to avoid flagging tiny placeholders in fixtures.
71
+ const GENERIC_SECRET_MIN_LENGTH = 8;
72
+ // AWS access keys use a 16-character suffix after the AKIA prefix.
73
+ const AWS_ACCESS_KEY_LENGTH = 16;
74
+ // GitHub PATs are much longer in practice; 20 keeps short test values out.
75
+ const GITHUB_TOKEN_MIN_LENGTH = 20;
76
+ const HARD_CODED_SECRET_PATTERNS = [
77
+ { pattern: new RegExp(`\\b(?:api[_-]?key|secret|token|password)\\b\\s*[:=]\\s*["'][^"']{${GENERIC_SECRET_MIN_LENGTH},}["']`, 'i'), title: 'Hardcoded secret-like assignment' },
78
+ { pattern: new RegExp(`\\bAKIA[0-9A-Z]{${AWS_ACCESS_KEY_LENGTH}}\\b`), title: 'AWS access key detected' },
79
+ { pattern: new RegExp(`\\bghp_[A-Za-z0-9]{${GITHUB_TOKEN_MIN_LENGTH},}\\b`), title: 'GitHub token detected' },
80
+ ];
81
+ const INJECTION_PATTERNS = [
82
+ { pattern: /\b(select|insert|update|delete)\b[\s\S]{0,160}\+\s*[A-Za-z_]/i, title: 'Possible SQL string concatenation' },
83
+ { pattern: /\b(exec|execSync|system|Runtime\.getRuntime\(\)\.exec)\s*\(/, title: 'Command execution sink detected' },
84
+ { pattern: /dangerouslySetInnerHTML|innerHTML\s*=/, title: 'Potential XSS sink detected' },
85
+ { pattern: /DocumentBuilderFactory\.newInstance\(\)/, title: 'Potential XXE parser usage detected' },
86
+ ];
87
+ const KAFKA_PATTERNS = [
88
+ { pattern: /\b(kafka|rabbitmq|amqplib|@KafkaListener|new Kafka\()/i, title: 'Message broker detected without TLS configuration' },
89
+ ];
90
+ const INSECURE_PATTERNS = [
91
+ { pattern: /NODE_TLS_REJECT_UNAUTHORIZED\s*=\s*["']?0["']?/, title: 'TLS verification disabled' },
92
+ { pattern: /\bverify\s*=\s*False\b/, title: 'TLS verification disabled in client call' },
93
+ { pattern: /http:\/\/[^\s'"]+/i, title: 'Plain HTTP endpoint detected' },
94
+ ];
95
+ function resolveSourceFiles(sourceGlob) {
96
+ if (!sourceGlob)
97
+ return [];
98
+ return fast_glob_1.default.sync(sourceGlob, { onlyFiles: true, absolute: true }).map((filePath) => ({
99
+ filePath,
100
+ content: fs.readFileSync(filePath, 'utf-8'),
101
+ }));
102
+ }
103
+ function isBinaryAvailable(binary) {
104
+ try {
105
+ (0, child_process_1.execFileSync)('which', [binary], { stdio: 'ignore' });
106
+ return true;
107
+ }
108
+ catch {
109
+ return false;
110
+ }
111
+ }
112
+ function resolvePipelineReportPath(explicitPath, configuredPath, autoLoadReports) {
113
+ if (explicitPath)
114
+ return path.resolve(explicitPath);
115
+ if (!autoLoadReports || !configuredPath)
116
+ return undefined;
117
+ const resolved = path.resolve(configuredPath);
118
+ return fs.existsSync(resolved) ? resolved : undefined;
119
+ }
120
+ function countBySeverity(findings) {
121
+ const counts = { ...ZERO_COUNTS };
122
+ for (const finding of findings) {
123
+ counts[finding.severity] += 1;
124
+ }
125
+ return counts;
126
+ }
127
+ function lineNumber(content, index) {
128
+ return content.slice(0, index).split('\n').length;
129
+ }
130
+ function ownFindingSeverity(title) {
131
+ const lowered = title.toLowerCase();
132
+ if (lowered.includes('aws'))
133
+ return 'CRITICAL';
134
+ if (lowered.includes('github') || lowered.includes('tls'))
135
+ return 'HIGH';
136
+ return 'MEDIUM';
137
+ }
138
+ function severityRank(severity) {
139
+ return { LOW: 1, MEDIUM: 2, HIGH: 3, CRITICAL: 4 }[severity];
140
+ }
141
+ function scanWithPatterns(files, patterns) {
142
+ var _a;
143
+ const findings = new Map();
144
+ for (const { filePath, content } of files) {
145
+ for (const { pattern, title } of patterns) {
146
+ const match = pattern.exec(content);
147
+ if (!match)
148
+ continue;
149
+ const finding = {
150
+ severity: ownFindingSeverity(title),
151
+ title,
152
+ filePath,
153
+ lineStart: lineNumber(content, match.index),
154
+ pattern: match[0].slice(0, 120),
155
+ };
156
+ const key = `${finding.filePath}:${(_a = finding.lineStart) !== null && _a !== void 0 ? _a : 0}`;
157
+ const existing = findings.get(key);
158
+ if (!existing || severityRank(finding.severity) > severityRank(existing.severity)) {
159
+ findings.set(key, finding);
160
+ }
161
+ }
162
+ }
163
+ return [...findings.values()];
164
+ }
165
+ function someFileMatches(files, pattern) {
166
+ for (const { content } of files) {
167
+ if (pattern.test(content)) {
168
+ return true;
169
+ }
170
+ }
171
+ return false;
172
+ }
173
+ async function loadSpec(specPath) {
174
+ return (await swagger_parser_1.default.validate(specPath));
175
+ }
176
+ function deriveZapTarget(spec) {
177
+ var _a, _b;
178
+ const serverUrl = (_b = (_a = spec.servers) === null || _a === void 0 ? void 0 : _a.find((server) => typeof server.url === 'string')) === null || _b === void 0 ? void 0 : _b.url;
179
+ return serverUrl && /^https?:\/\//i.test(serverUrl) ? serverUrl : undefined;
180
+ }
181
+ async function buildAuthCoverage(specPath, coverages, sourceFiles) {
182
+ var _a, _b, _c, _d;
183
+ const api = await loadSpec(specPath);
184
+ let endpointsTotal = 0;
185
+ let endpointsWithAuth = 0;
186
+ const endpointsMissingAuth = [];
187
+ for (const [routePath, pathItem] of Object.entries((_a = api.paths) !== null && _a !== void 0 ? _a : {})) {
188
+ for (const method of ['get', 'post', 'put', 'patch', 'delete', 'head', 'options']) {
189
+ const operation = pathItem === null || pathItem === void 0 ? void 0 : pathItem[method];
190
+ if (!operation)
191
+ continue;
192
+ endpointsTotal += 1;
193
+ const effectiveSecurity = (_b = operation.security) !== null && _b !== void 0 ? _b : api.security;
194
+ if (Array.isArray(effectiveSecurity) && effectiveSecurity.length > 0) {
195
+ endpointsWithAuth += 1;
196
+ }
197
+ else {
198
+ endpointsMissingAuth.push(`${method.toUpperCase()} ${routePath}`);
199
+ }
200
+ }
201
+ }
202
+ const securitySchemes = Object.values(((_d = (_c = api.components) === null || _c === void 0 ? void 0 : _c.securitySchemes) !== null && _d !== void 0 ? _d : {}));
203
+ const oauth2Detected = securitySchemes.some((scheme) => scheme.type === 'oauth2')
204
+ || someFileMatches(sourceFiles, /\boauth2\b/i);
205
+ const jwtDetected = securitySchemes.some((scheme) => { var _a; return scheme.type === 'http' && ((_a = scheme.scheme) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'bearer'; }) || someFileMatches(sourceFiles, /\b(jwt|bearer|@jwt_required|@PreAuthorize|passport\.authenticate\(['"]jwt)/i);
206
+ const testedAuthFlows = new Set(coverages
207
+ .filter((coverage) => coverage.covered && ['authentication', 'authorization', 'session-management'].includes(coverage.control.category))
208
+ .flatMap((coverage) => coverage.matchedTests)).size;
209
+ return {
210
+ source: 'own-scanner',
211
+ oauth2Detected,
212
+ jwtDetected,
213
+ endpointsWithAuth,
214
+ endpointsTotal,
215
+ endpointsMissingAuth,
216
+ testedAuthFlows,
217
+ };
218
+ }
219
+ function buildOwnScanFindings(sourceFiles) {
220
+ return {
221
+ source: 'own-scanner',
222
+ hardcodedSecrets: scanWithPatterns(sourceFiles, HARD_CODED_SECRET_PATTERNS),
223
+ injectionRisks: scanWithPatterns(sourceFiles, INJECTION_PATTERNS),
224
+ kafkaSecurityIssues: scanWithPatterns(sourceFiles, KAFKA_PATTERNS),
225
+ insecurePatterns: scanWithPatterns(sourceFiles, INSECURE_PATTERNS),
226
+ };
227
+ }
228
+ function enabledScanners(config) {
229
+ var _a, _b;
230
+ return new Set((_b = (_a = config.scans.security) === null || _a === void 0 ? void 0 : _a.scanners) !== null && _b !== void 0 ? _b : []);
231
+ }
232
+ async function runOptionalScanner(scanner, options, api) {
233
+ var _a;
234
+ const enabled = enabledScanners(options.config).has(scanner);
235
+ const pipelineConfig = options.config.security.pipeline;
236
+ const autoLoad = options.config.security.autoLoadReports !== false;
237
+ const workspace = path.resolve((_a = options.workspace) !== null && _a !== void 0 ? _a : '.');
238
+ if (scanner === 'semgrep') {
239
+ const reportPath = resolvePipelineReportPath(options.semgrepReport, pipelineConfig === null || pipelineConfig === void 0 ? void 0 : pipelineConfig.semgrepReport, autoLoad);
240
+ if (reportPath) {
241
+ return (0, semgrep_1.runSemgrep)({ enabled: true, mode: 'import', reportPath, config: 'p/security-audit' }, workspace);
242
+ }
243
+ if (enabled && isBinaryAvailable('semgrep')) {
244
+ return (0, semgrep_1.runSemgrep)({ enabled: true, mode: 'embedded', config: 'p/security-audit' }, workspace);
245
+ }
246
+ return undefined;
247
+ }
248
+ if (scanner === 'trivy') {
249
+ const reportPath = resolvePipelineReportPath(options.trivyReport, pipelineConfig === null || pipelineConfig === void 0 ? void 0 : pipelineConfig.trivyReport, autoLoad);
250
+ if (reportPath) {
251
+ return (0, trivy_1.runTrivy)({ enabled: true, mode: 'import', reportPath, scanners: ['vuln', 'secret', 'misconfig'] }, workspace);
252
+ }
253
+ if (enabled && isBinaryAvailable('trivy')) {
254
+ return (0, trivy_1.runTrivy)({ enabled: true, mode: 'embedded', scanners: ['vuln', 'secret', 'misconfig'] }, workspace);
255
+ }
256
+ return undefined;
257
+ }
258
+ if (scanner === 'gitleaks') {
259
+ const reportPath = resolvePipelineReportPath(options.gitleaksReport, pipelineConfig === null || pipelineConfig === void 0 ? void 0 : pipelineConfig.gitleaksReport, autoLoad);
260
+ if (reportPath) {
261
+ return (0, gitleaks_1.runGitleaks)({ enabled: true, mode: 'import', reportPath }, workspace);
262
+ }
263
+ if (enabled && isBinaryAvailable('gitleaks')) {
264
+ return (0, gitleaks_1.runGitleaks)({ enabled: true, mode: 'embedded' }, workspace);
265
+ }
266
+ return undefined;
267
+ }
268
+ const reportPath = resolvePipelineReportPath(options.zapReport, pipelineConfig === null || pipelineConfig === void 0 ? void 0 : pipelineConfig.zapReport, autoLoad);
269
+ if (reportPath) {
270
+ return (0, zap_1.runZap)({ enabled: true, mode: 'import', reportPath });
271
+ }
272
+ const targetUrl = deriveZapTarget(api);
273
+ if (enabled && targetUrl && isBinaryAvailable('zap-baseline.py')) {
274
+ return (0, zap_1.runZap)({ enabled: true, mode: 'embedded', targetUrl });
275
+ }
276
+ return undefined;
277
+ }
278
+ function buildSectionBase(scanner, findings, result) {
279
+ var _a, _b, _c, _d;
280
+ if (!result || (!result.success && findings.length === 0)) {
281
+ return {
282
+ source: null,
283
+ toolName: scanner,
284
+ reason: scanner === 'other'
285
+ ? 'Scanner not configured'
286
+ : `Configure ${scanner} in CI to enable ${SCANNER_ENABLEMENT_HELP[scanner]}.\n${CONFIGURE_COMMANDS[scanner]}`,
287
+ severityBreakdown: { ...ZERO_COUNTS },
288
+ topFindings: [],
289
+ };
290
+ }
291
+ return {
292
+ source: scanner,
293
+ toolName: scanner,
294
+ version: typeof ((_a = result.metadata) === null || _a === void 0 ? void 0 : _a.version) === 'string' ? result.metadata.version : undefined,
295
+ generatedAt: typeof ((_b = result.metadata) === null || _b === void 0 ? void 0 : _b.generatedAt) === 'string' ? result.metadata.generatedAt : undefined,
296
+ reportFile: typeof ((_c = result.metadata) === null || _c === void 0 ? void 0 : _c.reportFile) === 'string' ? result.metadata.reportFile : undefined,
297
+ fullReportLink: typeof ((_d = result.metadata) === null || _d === void 0 ? void 0 : _d.reportFile) === 'string'
298
+ ? path.relative(process.cwd(), result.metadata.reportFile)
299
+ : undefined,
300
+ reason: result.success ? undefined : result.error,
301
+ severityBreakdown: countBySeverity(findings),
302
+ topFindings: findings.slice(0, 5),
303
+ };
304
+ }
305
+ function ownFindingsToCriticalItems(ownFindings) {
306
+ return [
307
+ ...ownFindings.hardcodedSecrets,
308
+ ...ownFindings.injectionRisks,
309
+ ...ownFindings.kafkaSecurityIssues,
310
+ ...ownFindings.insecurePatterns,
311
+ ]
312
+ .filter((finding) => finding.severity === 'CRITICAL' || finding.severity === 'HIGH')
313
+ .slice(0, 10)
314
+ .map((finding) => ({
315
+ source: 'own-scanner',
316
+ severity: finding.severity,
317
+ title: finding.title,
318
+ file: path.relative(process.cwd(), finding.filePath),
319
+ line: finding.lineStart,
320
+ }));
321
+ }
322
+ function scannerFindingsToCriticalItems(source, findings) {
323
+ return findings
324
+ .filter((finding) => finding.severity === 'CRITICAL' || finding.severity === 'HIGH')
325
+ .slice(0, 10)
326
+ .map((finding) => ({
327
+ source,
328
+ severity: finding.severity,
329
+ title: finding.title,
330
+ file: finding.filePath,
331
+ line: finding.lineStart,
332
+ }));
333
+ }
334
+ function overallRisk(findings, ownFindings) {
335
+ const severities = [
336
+ ...findings.map((finding) => finding.severity),
337
+ ...ownFindings.hardcodedSecrets.map((finding) => finding.severity),
338
+ ...ownFindings.injectionRisks.map((finding) => finding.severity),
339
+ ...ownFindings.kafkaSecurityIssues.map((finding) => finding.severity),
340
+ ...ownFindings.insecurePatterns.map((finding) => finding.severity),
341
+ ];
342
+ if (severities.includes('CRITICAL'))
343
+ return 'CRITICAL';
344
+ if (severities.includes('HIGH'))
345
+ return 'HIGH';
346
+ if (severities.includes('MEDIUM'))
347
+ return 'MEDIUM';
348
+ return 'LOW';
349
+ }
350
+ async function generateSecurityFullReport(options) {
351
+ var _a, _b, _c, _d;
352
+ const sourceFiles = resolveSourceFiles(options.sourceGlob);
353
+ const ownScanFindings = buildOwnScanFindings(sourceFiles);
354
+ const authCoverage = await buildAuthCoverage(options.specPath, options.coverages, sourceFiles);
355
+ const api = await loadSpec(options.specPath);
356
+ const semgrepResult = await runOptionalScanner('semgrep', options, api);
357
+ const trivyResult = await runOptionalScanner('trivy', options, api);
358
+ const gitleaksResult = await runOptionalScanner('gitleaks', options, api);
359
+ const zapResult = await runOptionalScanner('zap', options, api);
360
+ const dependencyFindings = ((_a = trivyResult === null || trivyResult === void 0 ? void 0 : trivyResult.findings) !== null && _a !== void 0 ? _a : []).filter((finding) => finding.category === 'sca');
361
+ const sastFindings = (_b = semgrepResult === null || semgrepResult === void 0 ? void 0 : semgrepResult.findings) !== null && _b !== void 0 ? _b : [];
362
+ const secretFindings = (_c = gitleaksResult === null || gitleaksResult === void 0 ? void 0 : gitleaksResult.findings) !== null && _c !== void 0 ? _c : [];
363
+ const dastFindings = (_d = zapResult === null || zapResult === void 0 ? void 0 : zapResult.findings) !== null && _d !== void 0 ? _d : [];
364
+ const allScannerFindings = [
365
+ ...dependencyFindings,
366
+ ...sastFindings,
367
+ ...secretFindings,
368
+ ...dastFindings,
369
+ ];
370
+ const recommendations = [
371
+ authCoverage.endpointsMissingAuth.length > 0
372
+ ? `Add authentication/authorization coverage for: ${authCoverage.endpointsMissingAuth.slice(0, 5).join(', ')}`
373
+ : 'Authentication coverage looks complete for documented endpoints.',
374
+ !(trivyResult === null || trivyResult === void 0 ? void 0 : trivyResult.success)
375
+ ? `Configure trivy in CI: ${CONFIGURE_COMMANDS.trivy}`
376
+ : 'Review dependency findings and patch vulnerable packages first.',
377
+ !(gitleaksResult === null || gitleaksResult === void 0 ? void 0 : gitleaksResult.success)
378
+ ? `Configure gitleaks in CI: ${CONFIGURE_COMMANDS.gitleaks}`
379
+ : 'Rotate any discovered secrets and remove them from history.',
380
+ ];
381
+ return {
382
+ generatedAt: new Date().toISOString(),
383
+ authCoverage,
384
+ ownScanFindings,
385
+ dependencyScan: {
386
+ ...buildSectionBase('trivy', dependencyFindings, trivyResult),
387
+ vulnerabilities: dependencyFindings,
388
+ },
389
+ sastScan: {
390
+ ...buildSectionBase('semgrep', sastFindings, semgrepResult),
391
+ findings: sastFindings,
392
+ },
393
+ secretScan: {
394
+ ...buildSectionBase('gitleaks', secretFindings, gitleaksResult),
395
+ secrets: secretFindings,
396
+ },
397
+ dastScan: {
398
+ ...buildSectionBase('zap', dastFindings, zapResult),
399
+ findings: dastFindings,
400
+ },
401
+ riskSummary: {
402
+ overallRisk: overallRisk(allScannerFindings, ownScanFindings),
403
+ criticalItems: [
404
+ ...ownFindingsToCriticalItems(ownScanFindings),
405
+ ...scannerFindingsToCriticalItems('trivy', dependencyFindings),
406
+ ...scannerFindingsToCriticalItems('semgrep', sastFindings),
407
+ ...scannerFindingsToCriticalItems('gitleaks', secretFindings),
408
+ ...scannerFindingsToCriticalItems('zap', dastFindings),
409
+ ].slice(0, 10),
410
+ recommendations,
411
+ },
412
+ };
413
+ }
414
+ function writeSecurityFullReport(report, reportsDir) {
415
+ const resolvedDir = path.resolve(reportsDir);
416
+ fs.mkdirSync(resolvedDir, { recursive: true });
417
+ const filePath = path.join(resolvedDir, 'security-full.json');
418
+ fs.writeFileSync(filePath, JSON.stringify(report, null, 2), 'utf-8');
419
+ return filePath;
420
+ }
@@ -3,6 +3,7 @@ export * from './types';
3
3
  export { normalizeSemgrepOutput } from './normalizers/semgrep';
4
4
  export { normalizeTrivyOutput } from './normalizers/trivy';
5
5
  export { normalizeZapOutput } from './normalizers/zap';
6
+ export { normalizeGitleaksOutput } from './normalizers/gitleaks';
6
7
  export { evaluateSecurityGate } from './gate/index';
7
8
  /**
8
9
  * Run all configured security scanners and collect findings.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/security/index.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EAKnB,aAAa,EACd,MAAM,SAAS,CAAC;AAQjB,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAIpD;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,aAAa,EAAE,CAAC,CAkB1B;AAID;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,aAAa,EAAE,EACxB,MAAM,EAAE,kBAAkB,GACzB,mBAAmB,CAoDrB;AAID;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,mBAAmB,EAC5B,UAAU,EAAE,MAAM,GACjB,IAAI,CA2EN;AAuKD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,kBAAkB,EAC1B,UAAU,GAAE,MAAkB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAM9B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/security/index.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EAKnB,aAAa,EACd,MAAM,SAAS,CAAC;AASjB,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAIpD;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,aAAa,EAAE,CAAC,CAsB1B;AAID;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,aAAa,EAAE,EACxB,MAAM,EAAE,kBAAkB,GACzB,mBAAmB,CAoDrB;AAID;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,mBAAmB,EAC5B,UAAU,EAAE,MAAM,GACjB,IAAI,CA2EN;AAuKD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,kBAAkB,EAC1B,UAAU,GAAE,MAAkB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAM9B"}
@@ -36,7 +36,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
36
36
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.evaluateSecurityGate = exports.normalizeZapOutput = exports.normalizeTrivyOutput = exports.normalizeSemgrepOutput = void 0;
39
+ exports.evaluateSecurityGate = exports.normalizeGitleaksOutput = exports.normalizeZapOutput = exports.normalizeTrivyOutput = exports.normalizeSemgrepOutput = void 0;
40
40
  exports.runSecurityScanners = runSecurityScanners;
41
41
  exports.buildSecurityScanSummary = buildSecurityScanSummary;
42
42
  exports.generateSecurityScanReports = generateSecurityScanReports;
@@ -51,6 +51,7 @@ const path = __importStar(require("path"));
51
51
  const semgrep_1 = require("./scanners/semgrep");
52
52
  const trivy_1 = require("./scanners/trivy");
53
53
  const zap_1 = require("./scanners/zap");
54
+ const gitleaks_1 = require("./scanners/gitleaks");
54
55
  const index_1 = require("./gate/index");
55
56
  // ─── Re-exports ───────────────────────────────────────────────────────────────
56
57
  __exportStar(require("./types"), exports);
@@ -60,6 +61,8 @@ var trivy_2 = require("./normalizers/trivy");
60
61
  Object.defineProperty(exports, "normalizeTrivyOutput", { enumerable: true, get: function () { return trivy_2.normalizeTrivyOutput; } });
61
62
  var zap_2 = require("./normalizers/zap");
62
63
  Object.defineProperty(exports, "normalizeZapOutput", { enumerable: true, get: function () { return zap_2.normalizeZapOutput; } });
64
+ var gitleaks_2 = require("./normalizers/gitleaks");
65
+ Object.defineProperty(exports, "normalizeGitleaksOutput", { enumerable: true, get: function () { return gitleaks_2.normalizeGitleaksOutput; } });
63
66
  var index_2 = require("./gate/index");
64
67
  Object.defineProperty(exports, "evaluateSecurityGate", { enumerable: true, get: function () { return index_2.evaluateSecurityGate; } });
65
68
  // ─── Scanner orchestration ────────────────────────────────────────────────────
@@ -67,7 +70,7 @@ Object.defineProperty(exports, "evaluateSecurityGate", { enumerable: true, get:
67
70
  * Run all configured security scanners and collect findings.
68
71
  */
69
72
  async function runSecurityScanners(config) {
70
- var _a, _b, _c, _d, _e;
73
+ var _a, _b, _c, _d, _e, _f;
71
74
  const workspace = path.resolve((_a = config.workspace) !== null && _a !== void 0 ? _a : '.');
72
75
  const results = [];
73
76
  const scanners = (_b = config.scanners) !== null && _b !== void 0 ? _b : {};
@@ -80,6 +83,9 @@ async function runSecurityScanners(config) {
80
83
  if ((_e = scanners.zap) === null || _e === void 0 ? void 0 : _e.enabled) {
81
84
  results.push(await (0, zap_1.runZap)(scanners.zap));
82
85
  }
86
+ if ((_f = scanners.gitleaks) === null || _f === void 0 ? void 0 : _f.enabled) {
87
+ results.push(await (0, gitleaks_1.runGitleaks)(scanners.gitleaks, workspace));
88
+ }
83
89
  return results;
84
90
  }
85
91
  // ─── Summary builder ──────────────────────────────────────────────────────────
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Gitleaks output normalizer.
3
+ * Converts Gitleaks JSON findings to the common SecurityFinding model.
4
+ */
5
+ import { SecurityFinding } from '../types';
6
+ export declare function normalizeGitleaksOutput(raw: unknown): SecurityFinding[];
7
+ //# sourceMappingURL=gitleaks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitleaks.d.ts","sourceRoot":"","sources":["../../../../src/security/normalizers/gitleaks.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,eAAe,EAAmB,MAAM,UAAU,CAAC;AA4B5D,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,EAAE,CAgBvE"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeGitleaksOutput = normalizeGitleaksOutput;
4
+ const GITLEAKS_CRITICAL_MARKERS = ['private-key', 'rsa'];
5
+ const GITLEAKS_HIGH_MARKERS = ['token', 'aws', 'github'];
6
+ function mapGitleaksSeverity(tags, ruleId) {
7
+ const values = [...(tags !== null && tags !== void 0 ? tags : []), ruleId !== null && ruleId !== void 0 ? ruleId : ''].map((value) => value.toLowerCase());
8
+ if (values.some((value) => GITLEAKS_CRITICAL_MARKERS.some((marker) => value.includes(marker))))
9
+ return 'CRITICAL';
10
+ if (values.some((value) => GITLEAKS_HIGH_MARKERS.some((marker) => value.includes(marker))))
11
+ return 'HIGH';
12
+ return 'MEDIUM';
13
+ }
14
+ function normalizeGitleaksOutput(raw) {
15
+ const findings = Array.isArray(raw) ? raw : [];
16
+ return findings.map((finding) => {
17
+ var _a, _b, _c, _d;
18
+ return ({
19
+ scanner: 'gitleaks',
20
+ category: 'secret',
21
+ severity: mapGitleaksSeverity(finding.Tags, finding.RuleID),
22
+ title: (_b = (_a = finding.Description) !== null && _a !== void 0 ? _a : finding.RuleID) !== null && _b !== void 0 ? _b : 'Secret detected',
23
+ description: (_c = finding.Match) !== null && _c !== void 0 ? _c : finding.Secret,
24
+ ruleId: finding.RuleID,
25
+ filePath: (_d = finding.File) !== null && _d !== void 0 ? _d : finding.SymlinkFile,
26
+ lineStart: finding.StartLine,
27
+ lineEnd: finding.EndLine,
28
+ secretType: finding.RuleID,
29
+ scannerNativePayload: finding,
30
+ });
31
+ });
32
+ }
@@ -0,0 +1,3 @@
1
+ import { GitleaksScannerConfig, ScannerResult } from '../types';
2
+ export declare function runGitleaks(config: GitleaksScannerConfig, workspace?: string): Promise<ScannerResult>;
3
+ //# sourceMappingURL=gitleaks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitleaks.d.ts","sourceRoot":"","sources":["../../../../src/security/scanners/gitleaks.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,qBAAqB,EAAmB,aAAa,EAAE,MAAM,UAAU,CAAC;AAuCjF,wBAAsB,WAAW,CAC/B,MAAM,EAAE,qBAAqB,EAC7B,SAAS,GAAE,MAAY,GACtB,OAAO,CAAC,aAAa,CAAC,CAuCxB"}