api-tests-coverage 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +703 -0
- package/config.yaml.example +227 -0
- package/dist/action/src/index.d.ts +2 -0
- package/dist/action/src/index.d.ts.map +1 -0
- package/dist/action/src/index.js +349 -0
- package/dist/action/src/prComment.d.ts +34 -0
- package/dist/action/src/prComment.d.ts.map +1 -0
- package/dist/action/src/prComment.js +146 -0
- package/dist/src/ast/astAnalysisOrchestrator.d.ts +36 -0
- package/dist/src/ast/astAnalysisOrchestrator.d.ts.map +1 -0
- package/dist/src/ast/astAnalysisOrchestrator.js +123 -0
- package/dist/src/ast/astTypes.d.ts +105 -0
- package/dist/src/ast/astTypes.d.ts.map +1 -0
- package/dist/src/ast/astTypes.js +9 -0
- package/dist/src/ast/languageAnalyzer.d.ts +46 -0
- package/dist/src/ast/languageAnalyzer.d.ts.map +1 -0
- package/dist/src/ast/languageAnalyzer.js +9 -0
- package/dist/src/ast/languageCapabilities.d.ts +24 -0
- package/dist/src/ast/languageCapabilities.d.ts.map +1 -0
- package/dist/src/ast/languageCapabilities.js +92 -0
- package/dist/src/ast/parseFile.d.ts +16 -0
- package/dist/src/ast/parseFile.d.ts.map +1 -0
- package/dist/src/ast/parseFile.js +65 -0
- package/dist/src/ast/parserRegistry.d.ts +39 -0
- package/dist/src/ast/parserRegistry.d.ts.map +1 -0
- package/dist/src/ast/parserRegistry.js +66 -0
- package/dist/src/buildSummary.d.ts +26 -0
- package/dist/src/buildSummary.d.ts.map +1 -0
- package/dist/src/buildSummary.js +193 -0
- package/dist/src/businessCoverage.d.ts +68 -0
- package/dist/src/businessCoverage.d.ts.map +1 -0
- package/dist/src/businessCoverage.js +290 -0
- package/dist/src/compatibilityCoverage.d.ts +83 -0
- package/dist/src/compatibilityCoverage.d.ts.map +1 -0
- package/dist/src/compatibilityCoverage.js +501 -0
- package/dist/src/config/defaultConfig.d.ts +9 -0
- package/dist/src/config/defaultConfig.d.ts.map +1 -0
- package/dist/src/config/defaultConfig.js +97 -0
- package/dist/src/config/index.d.ts +12 -0
- package/dist/src/config/index.d.ts.map +1 -0
- package/dist/src/config/index.js +37 -0
- package/dist/src/config/loadConfig.d.ts +29 -0
- package/dist/src/config/loadConfig.d.ts.map +1 -0
- package/dist/src/config/loadConfig.js +135 -0
- package/dist/src/config/mergeConfig.d.ts +15 -0
- package/dist/src/config/mergeConfig.d.ts.map +1 -0
- package/dist/src/config/mergeConfig.js +57 -0
- package/dist/src/config/schema.d.ts +15 -0
- package/dist/src/config/schema.d.ts.map +1 -0
- package/dist/src/config/schema.js +30 -0
- package/dist/src/config/types.d.ts +175 -0
- package/dist/src/config/types.d.ts.map +1 -0
- package/dist/src/config/types.js +9 -0
- package/dist/src/config/validateConfig.d.ts +22 -0
- package/dist/src/config/validateConfig.d.ts.map +1 -0
- package/dist/src/config/validateConfig.js +171 -0
- package/dist/src/config.d.ts +168 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +204 -0
- package/dist/src/coverage/deep-analysis/callGraph.d.ts +67 -0
- package/dist/src/coverage/deep-analysis/callGraph.d.ts.map +1 -0
- package/dist/src/coverage/deep-analysis/callGraph.js +275 -0
- package/dist/src/coverage/deep-analysis/deepEndpointResolver.d.ts +23 -0
- package/dist/src/coverage/deep-analysis/deepEndpointResolver.d.ts.map +1 -0
- package/dist/src/coverage/deep-analysis/deepEndpointResolver.js +394 -0
- package/dist/src/coverage/deep-analysis/index.d.ts +17 -0
- package/dist/src/coverage/deep-analysis/index.d.ts.map +1 -0
- package/dist/src/coverage/deep-analysis/index.js +63 -0
- package/dist/src/coverage/deep-analysis/resolveAssertions.d.ts +60 -0
- package/dist/src/coverage/deep-analysis/resolveAssertions.d.ts.map +1 -0
- package/dist/src/coverage/deep-analysis/resolveAssertions.js +121 -0
- package/dist/src/coverage/deep-analysis/resolveConstants.d.ts +36 -0
- package/dist/src/coverage/deep-analysis/resolveConstants.d.ts.map +1 -0
- package/dist/src/coverage/deep-analysis/resolveConstants.js +92 -0
- package/dist/src/coverage/deep-analysis/resolveEnums.d.ts +55 -0
- package/dist/src/coverage/deep-analysis/resolveEnums.d.ts.map +1 -0
- package/dist/src/coverage/deep-analysis/resolveEnums.js +152 -0
- package/dist/src/coverage/deep-analysis/resolveMethodChains.d.ts +70 -0
- package/dist/src/coverage/deep-analysis/resolveMethodChains.d.ts.map +1 -0
- package/dist/src/coverage/deep-analysis/resolveMethodChains.js +152 -0
- package/dist/src/coverage/deep-analysis/resolvePaths.d.ts +80 -0
- package/dist/src/coverage/deep-analysis/resolvePaths.d.ts.map +1 -0
- package/dist/src/coverage/deep-analysis/resolvePaths.js +216 -0
- package/dist/src/coverage/deep-analysis/resolveRequestWrappers.d.ts +71 -0
- package/dist/src/coverage/deep-analysis/resolveRequestWrappers.d.ts.map +1 -0
- package/dist/src/coverage/deep-analysis/resolveRequestWrappers.js +226 -0
- package/dist/src/coverage/deep-analysis/symbolTable.d.ts +58 -0
- package/dist/src/coverage/deep-analysis/symbolTable.d.ts.map +1 -0
- package/dist/src/coverage/deep-analysis/symbolTable.js +230 -0
- package/dist/src/coverage/deep-analysis/types.d.ts +122 -0
- package/dist/src/coverage/deep-analysis/types.d.ts.map +1 -0
- package/dist/src/coverage/deep-analysis/types.js +21 -0
- package/dist/src/discovery/fileClassifier.d.ts +50 -0
- package/dist/src/discovery/fileClassifier.d.ts.map +1 -0
- package/dist/src/discovery/fileClassifier.js +238 -0
- package/dist/src/discovery/projectDiscovery.d.ts +66 -0
- package/dist/src/discovery/projectDiscovery.d.ts.map +1 -0
- package/dist/src/discovery/projectDiscovery.js +287 -0
- package/dist/src/endpointCoverage.d.ts +70 -0
- package/dist/src/endpointCoverage.d.ts.map +1 -0
- package/dist/src/endpointCoverage.js +381 -0
- package/dist/src/errorCoverage.d.ts +93 -0
- package/dist/src/errorCoverage.d.ts.map +1 -0
- package/dist/src/errorCoverage.js +698 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +1441 -0
- package/dist/src/inference/businessRuleInference.d.ts +63 -0
- package/dist/src/inference/businessRuleInference.d.ts.map +1 -0
- package/dist/src/inference/businessRuleInference.js +268 -0
- package/dist/src/inference/integrationFlowInference.d.ts +56 -0
- package/dist/src/inference/integrationFlowInference.d.ts.map +1 -0
- package/dist/src/inference/integrationFlowInference.js +266 -0
- package/dist/src/integrationCoverage.d.ts +72 -0
- package/dist/src/integrationCoverage.d.ts.map +1 -0
- package/dist/src/integrationCoverage.js +317 -0
- package/dist/src/intelligence/index.d.ts +20 -0
- package/dist/src/intelligence/index.d.ts.map +1 -0
- package/dist/src/intelligence/index.js +105 -0
- package/dist/src/intelligence/linkageEngine.d.ts +20 -0
- package/dist/src/intelligence/linkageEngine.d.ts.map +1 -0
- package/dist/src/intelligence/linkageEngine.js +522 -0
- package/dist/src/intelligence/markdownReporter.d.ts +12 -0
- package/dist/src/intelligence/markdownReporter.d.ts.map +1 -0
- package/dist/src/intelligence/markdownReporter.js +265 -0
- package/dist/src/intelligence/riskScoring.d.ts +53 -0
- package/dist/src/intelligence/riskScoring.d.ts.map +1 -0
- package/dist/src/intelligence/riskScoring.js +181 -0
- package/dist/src/intelligence/types.d.ts +121 -0
- package/dist/src/intelligence/types.d.ts.map +1 -0
- package/dist/src/intelligence/types.js +8 -0
- package/dist/src/languageDetection.d.ts +100 -0
- package/dist/src/languageDetection.d.ts.map +1 -0
- package/dist/src/languageDetection.js +349 -0
- package/dist/src/languages/java/index.d.ts +16 -0
- package/dist/src/languages/java/index.d.ts.map +1 -0
- package/dist/src/languages/java/index.js +103 -0
- package/dist/src/languages/java/parser.d.ts +7 -0
- package/dist/src/languages/java/parser.d.ts.map +1 -0
- package/dist/src/languages/java/parser.js +50 -0
- package/dist/src/languages/java/semanticBuilder.d.ts +21 -0
- package/dist/src/languages/java/semanticBuilder.d.ts.map +1 -0
- package/dist/src/languages/java/semanticBuilder.js +358 -0
- package/dist/src/languages/javascript/annotationExtractor.d.ts +20 -0
- package/dist/src/languages/javascript/annotationExtractor.d.ts.map +1 -0
- package/dist/src/languages/javascript/annotationExtractor.js +94 -0
- package/dist/src/languages/javascript/assertionResolver.d.ts +18 -0
- package/dist/src/languages/javascript/assertionResolver.d.ts.map +1 -0
- package/dist/src/languages/javascript/assertionResolver.js +150 -0
- package/dist/src/languages/javascript/callResolver.d.ts +23 -0
- package/dist/src/languages/javascript/callResolver.d.ts.map +1 -0
- package/dist/src/languages/javascript/callResolver.js +236 -0
- package/dist/src/languages/javascript/httpInteractionExtractor.d.ts +23 -0
- package/dist/src/languages/javascript/httpInteractionExtractor.d.ts.map +1 -0
- package/dist/src/languages/javascript/httpInteractionExtractor.js +205 -0
- package/dist/src/languages/javascript/index.d.ts +20 -0
- package/dist/src/languages/javascript/index.d.ts.map +1 -0
- package/dist/src/languages/javascript/index.js +136 -0
- package/dist/src/languages/javascript/parser.d.ts +14 -0
- package/dist/src/languages/javascript/parser.d.ts.map +1 -0
- package/dist/src/languages/javascript/parser.js +38 -0
- package/dist/src/languages/javascript/symbolResolver.d.ts +31 -0
- package/dist/src/languages/javascript/symbolResolver.d.ts.map +1 -0
- package/dist/src/languages/javascript/symbolResolver.js +183 -0
- package/dist/src/languages/kotlin/index.d.ts +16 -0
- package/dist/src/languages/kotlin/index.d.ts.map +1 -0
- package/dist/src/languages/kotlin/index.js +151 -0
- package/dist/src/languages/kotlin/parser.d.ts +11 -0
- package/dist/src/languages/kotlin/parser.d.ts.map +1 -0
- package/dist/src/languages/kotlin/parser.js +74 -0
- package/dist/src/languages/python/index.d.ts +15 -0
- package/dist/src/languages/python/index.d.ts.map +1 -0
- package/dist/src/languages/python/index.js +293 -0
- package/dist/src/languages/ruby/index.d.ts +15 -0
- package/dist/src/languages/ruby/index.d.ts.map +1 -0
- package/dist/src/languages/ruby/index.js +274 -0
- package/dist/src/languages/shared/treeSitterUtils.d.ts +43 -0
- package/dist/src/languages/shared/treeSitterUtils.d.ts.map +1 -0
- package/dist/src/languages/shared/treeSitterUtils.js +100 -0
- package/dist/src/languages/typescript/index.d.ts +14 -0
- package/dist/src/languages/typescript/index.d.ts.map +1 -0
- package/dist/src/languages/typescript/index.js +25 -0
- package/dist/src/lib/index.d.ts +228 -0
- package/dist/src/lib/index.d.ts.map +1 -0
- package/dist/src/lib/index.js +486 -0
- package/dist/src/mcp/client/index.d.ts +37 -0
- package/dist/src/mcp/client/index.d.ts.map +1 -0
- package/dist/src/mcp/client/index.js +235 -0
- package/dist/src/mcp/config.d.ts +50 -0
- package/dist/src/mcp/config.d.ts.map +1 -0
- package/dist/src/mcp/config.js +125 -0
- package/dist/src/mcp/events.d.ts +24 -0
- package/dist/src/mcp/events.d.ts.map +1 -0
- package/dist/src/mcp/events.js +48 -0
- package/dist/src/mcp/fallback/index.d.ts +50 -0
- package/dist/src/mcp/fallback/index.d.ts.map +1 -0
- package/dist/src/mcp/fallback/index.js +216 -0
- package/dist/src/mcp/index.d.ts +67 -0
- package/dist/src/mcp/index.d.ts.map +1 -0
- package/dist/src/mcp/index.js +212 -0
- package/dist/src/mcp/normalizer.d.ts +21 -0
- package/dist/src/mcp/normalizer.d.ts.map +1 -0
- package/dist/src/mcp/normalizer.js +99 -0
- package/dist/src/mcp/prompts/index.d.ts +86 -0
- package/dist/src/mcp/prompts/index.d.ts.map +1 -0
- package/dist/src/mcp/prompts/index.js +304 -0
- package/dist/src/mcp/templates/index.d.ts +35 -0
- package/dist/src/mcp/templates/index.d.ts.map +1 -0
- package/dist/src/mcp/templates/index.js +143 -0
- package/dist/src/mcp/testing/mock-server/index.d.ts +47 -0
- package/dist/src/mcp/testing/mock-server/index.d.ts.map +1 -0
- package/dist/src/mcp/testing/mock-server/index.js +157 -0
- package/dist/src/mcp/types.d.ts +127 -0
- package/dist/src/mcp/types.d.ts.map +1 -0
- package/dist/src/mcp/types.js +8 -0
- package/dist/src/observability.d.ts +138 -0
- package/dist/src/observability.d.ts.map +1 -0
- package/dist/src/observability.js +519 -0
- package/dist/src/parameterCoverage.d.ts +75 -0
- package/dist/src/parameterCoverage.d.ts.map +1 -0
- package/dist/src/parameterCoverage.js +629 -0
- package/dist/src/perfResilienceCoverage.d.ts +155 -0
- package/dist/src/perfResilienceCoverage.d.ts.map +1 -0
- package/dist/src/perfResilienceCoverage.js +670 -0
- package/dist/src/pluginLoader.d.ts +51 -0
- package/dist/src/pluginLoader.d.ts.map +1 -0
- package/dist/src/pluginLoader.js +72 -0
- package/dist/src/publishing.d.ts +63 -0
- package/dist/src/publishing.d.ts.map +1 -0
- package/dist/src/publishing.js +379 -0
- package/dist/src/qualityGate.d.ts +58 -0
- package/dist/src/qualityGate.d.ts.map +1 -0
- package/dist/src/qualityGate.js +118 -0
- package/dist/src/reporting.d.ts +41 -0
- package/dist/src/reporting.d.ts.map +1 -0
- package/dist/src/reporting.js +278 -0
- package/dist/src/screenshots.d.ts +71 -0
- package/dist/src/screenshots.d.ts.map +1 -0
- package/dist/src/screenshots.js +141 -0
- package/dist/src/security/gate/index.d.ts +11 -0
- package/dist/src/security/gate/index.d.ts.map +1 -0
- package/dist/src/security/gate/index.js +65 -0
- package/dist/src/security/index.d.ts +30 -0
- package/dist/src/security/index.d.ts.map +1 -0
- package/dist/src/security/index.js +342 -0
- package/dist/src/security/normalizers/semgrep.d.ts +10 -0
- package/dist/src/security/normalizers/semgrep.d.ts.map +1 -0
- package/dist/src/security/normalizers/semgrep.js +104 -0
- package/dist/src/security/normalizers/trivy.d.ts +10 -0
- package/dist/src/security/normalizers/trivy.d.ts.map +1 -0
- package/dist/src/security/normalizers/trivy.js +78 -0
- package/dist/src/security/normalizers/zap.d.ts +10 -0
- package/dist/src/security/normalizers/zap.d.ts.map +1 -0
- package/dist/src/security/normalizers/zap.js +104 -0
- package/dist/src/security/scanners/semgrep.d.ts +6 -0
- package/dist/src/security/scanners/semgrep.d.ts.map +1 -0
- package/dist/src/security/scanners/semgrep.js +125 -0
- package/dist/src/security/scanners/trivy.d.ts +6 -0
- package/dist/src/security/scanners/trivy.d.ts.map +1 -0
- package/dist/src/security/scanners/trivy.js +115 -0
- package/dist/src/security/scanners/zap.d.ts +6 -0
- package/dist/src/security/scanners/zap.d.ts.map +1 -0
- package/dist/src/security/scanners/zap.js +135 -0
- package/dist/src/security/types.d.ts +146 -0
- package/dist/src/security/types.d.ts.map +1 -0
- package/dist/src/security/types.js +6 -0
- package/dist/src/securityCoverage.d.ts +116 -0
- package/dist/src/securityCoverage.d.ts.map +1 -0
- package/dist/src/securityCoverage.js +725 -0
- package/dist/src/summary/buildSummary.d.ts +28 -0
- package/dist/src/summary/buildSummary.d.ts.map +1 -0
- package/dist/src/summary/buildSummary.js +257 -0
- package/dist/src/summary/evaluateMetrics.d.ts +31 -0
- package/dist/src/summary/evaluateMetrics.d.ts.map +1 -0
- package/dist/src/summary/evaluateMetrics.js +118 -0
- package/dist/src/summary/index.d.ts +10 -0
- package/dist/src/summary/index.d.ts.map +1 -0
- package/dist/src/summary/index.js +22 -0
- package/dist/src/summary/markdownRenderer.d.ts +139 -0
- package/dist/src/summary/markdownRenderer.d.ts.map +1 -0
- package/dist/src/summary/markdownRenderer.js +459 -0
- package/dist/src/summary/prSummary.d.ts +24 -0
- package/dist/src/summary/prSummary.d.ts.map +1 -0
- package/dist/src/summary/prSummary.js +233 -0
- package/dist/src/summary/summaryTypes.d.ts +35 -0
- package/dist/src/summary/summaryTypes.d.ts.map +1 -0
- package/dist/src/summary/summaryTypes.js +27 -0
- package/package.json +84 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OWASP ZAP output normalizer.
|
|
3
|
+
* Converts ZAP JSON/XML findings to the common SecurityFinding model.
|
|
4
|
+
*/
|
|
5
|
+
import { SecurityFinding } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* Parse ZAP JSON output and return normalized SecurityFindings.
|
|
8
|
+
*/
|
|
9
|
+
export declare function normalizeZapOutput(raw: unknown): SecurityFinding[];
|
|
10
|
+
//# sourceMappingURL=zap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zap.d.ts","sourceRoot":"","sources":["../../../../src/security/normalizers/zap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,eAAe,EAGhB,MAAM,UAAU,CAAC;AA2HlB;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,EAAE,CAyBlE"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeZapOutput = normalizeZapOutput;
|
|
4
|
+
// ─── Severity mapping ─────────────────────────────────────────────────────────
|
|
5
|
+
function mapZapSeverity(riskdesc, riskcode) {
|
|
6
|
+
const desc = (riskdesc !== null && riskdesc !== void 0 ? riskdesc : '').toLowerCase();
|
|
7
|
+
const code = Number(riskcode !== null && riskcode !== void 0 ? riskcode : -1);
|
|
8
|
+
if (desc.startsWith('critical') || code === 4)
|
|
9
|
+
return 'CRITICAL';
|
|
10
|
+
if (desc.startsWith('high') || code === 3)
|
|
11
|
+
return 'HIGH';
|
|
12
|
+
if (desc.startsWith('medium') || code === 2)
|
|
13
|
+
return 'MEDIUM';
|
|
14
|
+
return 'LOW';
|
|
15
|
+
}
|
|
16
|
+
// ─── Category mapping ─────────────────────────────────────────────────────────
|
|
17
|
+
const ZAP_CATEGORY_PATTERNS = [
|
|
18
|
+
{ pattern: /authentication|csrf|anti.forgery|brute.force|session.fixation|auth.bypass/i, category: 'auth' },
|
|
19
|
+
{ pattern: /authorization|access.control|privilege|insecure.direct.object/i, category: 'auth' },
|
|
20
|
+
{ pattern: /ssl|tls|certificate|cipher|transport.security|https|weak.cipher|insecure.transport/i, category: 'crypto' },
|
|
21
|
+
{ pattern: /information.disclosure|sensitive.data|data.exposure|stack.trace|error.message|server.banner/i, category: 'data-exposure' },
|
|
22
|
+
{ pattern: /misconfiguration|security.header|csp|cors|clickjacking|x.frame|x.content.type/i, category: 'misconfig' },
|
|
23
|
+
{ pattern: /session|cookie|samesite|httponly|secure.flag/i, category: 'auth' },
|
|
24
|
+
{ pattern: /injection|sqli|xss|cross.site|path.traversal|parameter.tamper|directory.traversal|template.injection|command.injection/i, category: 'injection' },
|
|
25
|
+
];
|
|
26
|
+
function mapZapCategory(alertName) {
|
|
27
|
+
for (const { pattern, category } of ZAP_CATEGORY_PATTERNS) {
|
|
28
|
+
if (pattern.test(alertName))
|
|
29
|
+
return category;
|
|
30
|
+
}
|
|
31
|
+
return 'dast';
|
|
32
|
+
}
|
|
33
|
+
function parseEndpoint(uri) {
|
|
34
|
+
if (!uri)
|
|
35
|
+
return undefined;
|
|
36
|
+
try {
|
|
37
|
+
const url = new URL(uri);
|
|
38
|
+
return { path: url.pathname };
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return { path: uri };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// ─── Alert extraction ─────────────────────────────────────────────────────────
|
|
45
|
+
function extractAlerts(data) {
|
|
46
|
+
// Top-level alerts array
|
|
47
|
+
if (Array.isArray(data.alerts) && data.alerts.length > 0) {
|
|
48
|
+
return data.alerts;
|
|
49
|
+
}
|
|
50
|
+
// site.alerts (single or array of sites)
|
|
51
|
+
const sites = data.site
|
|
52
|
+
? Array.isArray(data.site)
|
|
53
|
+
? data.site
|
|
54
|
+
: [data.site]
|
|
55
|
+
: [];
|
|
56
|
+
const alerts = [];
|
|
57
|
+
for (const site of sites) {
|
|
58
|
+
if (Array.isArray(site.alerts)) {
|
|
59
|
+
alerts.push(...site.alerts);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Fallback: look for top-level key that looks like alerts
|
|
63
|
+
if (alerts.length === 0) {
|
|
64
|
+
for (const value of Object.values(data)) {
|
|
65
|
+
if (Array.isArray(value) && value.length > 0 && value[0] && typeof value[0] === 'object') {
|
|
66
|
+
const first = value[0];
|
|
67
|
+
if ('alert' in first || 'name' in first || 'riskdesc' in first) {
|
|
68
|
+
alerts.push(...value);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return alerts;
|
|
75
|
+
}
|
|
76
|
+
// ─── Normalizer ───────────────────────────────────────────────────────────────
|
|
77
|
+
/**
|
|
78
|
+
* Parse ZAP JSON output and return normalized SecurityFindings.
|
|
79
|
+
*/
|
|
80
|
+
function normalizeZapOutput(raw) {
|
|
81
|
+
const data = raw;
|
|
82
|
+
const alerts = extractAlerts(data);
|
|
83
|
+
return alerts.map((alert) => {
|
|
84
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
85
|
+
const name = (_b = (_a = alert.alert) !== null && _a !== void 0 ? _a : alert.name) !== null && _b !== void 0 ? _b : 'Unknown ZAP finding';
|
|
86
|
+
const uri = (_d = (_c = alert.uri) !== null && _c !== void 0 ? _c : alert.url) !== null && _d !== void 0 ? _d : (_f = (_e = alert.instances) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.uri;
|
|
87
|
+
const method = (_g = alert.method) !== null && _g !== void 0 ? _g : (_j = (_h = alert.instances) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.method;
|
|
88
|
+
return {
|
|
89
|
+
scanner: 'zap',
|
|
90
|
+
category: mapZapCategory(name),
|
|
91
|
+
severity: mapZapSeverity(alert.riskdesc, alert.riskcode),
|
|
92
|
+
title: name,
|
|
93
|
+
description: alert.description,
|
|
94
|
+
ruleId: (_k = alert.pluginid) !== null && _k !== void 0 ? _k : alert.sourceid,
|
|
95
|
+
cwe: alert.cweid ? [`CWE-${alert.cweid}`] : undefined,
|
|
96
|
+
endpoint: uri
|
|
97
|
+
? { ...parseEndpoint(uri), method: method === null || method === void 0 ? void 0 : method.toUpperCase() }
|
|
98
|
+
: method
|
|
99
|
+
? { method: method.toUpperCase() }
|
|
100
|
+
: undefined,
|
|
101
|
+
scannerNativePayload: alert,
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SemgrepScannerConfig, ScannerResult } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Run the Semgrep scanner according to the given configuration.
|
|
4
|
+
*/
|
|
5
|
+
export declare function runSemgrep(config: SemgrepScannerConfig, workspace?: string): Promise<ScannerResult>;
|
|
6
|
+
//# sourceMappingURL=semgrep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semgrep.d.ts","sourceRoot":"","sources":["../../../../src/security/scanners/semgrep.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,oBAAoB,EAAmB,aAAa,EAAE,MAAM,UAAU,CAAC;AAkEhF;;GAEG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,oBAAoB,EAC5B,SAAS,GAAE,MAAY,GACtB,OAAO,CAAC,aAAa,CAAC,CAuBxB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runSemgrep = runSemgrep;
|
|
37
|
+
/**
|
|
38
|
+
* Semgrep scanner integration.
|
|
39
|
+
* Supports embedded (binary) and import (pre-generated JSON) modes.
|
|
40
|
+
*/
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const child_process_1 = require("child_process");
|
|
44
|
+
const util_1 = require("util");
|
|
45
|
+
const semgrep_1 = require("../normalizers/semgrep");
|
|
46
|
+
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
47
|
+
/**
|
|
48
|
+
* Run Semgrep in embedded mode.
|
|
49
|
+
* Invokes the `semgrep` binary and parses its JSON output.
|
|
50
|
+
*/
|
|
51
|
+
async function runEmbedded(config, workspace) {
|
|
52
|
+
var _a, _b, _c;
|
|
53
|
+
const binary = (_a = config.binaryPath) !== null && _a !== void 0 ? _a : 'semgrep';
|
|
54
|
+
const semgrepConfig = (_b = config.config) !== null && _b !== void 0 ? _b : 'p/default';
|
|
55
|
+
const timeout = ((_c = config.timeout) !== null && _c !== void 0 ? _c : 120) * 1000;
|
|
56
|
+
const args = [
|
|
57
|
+
'scan',
|
|
58
|
+
'--json',
|
|
59
|
+
'--config', semgrepConfig,
|
|
60
|
+
];
|
|
61
|
+
if (config.include && config.include.length > 0) {
|
|
62
|
+
for (const inc of config.include) {
|
|
63
|
+
args.push('--include', inc);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (config.exclude && config.exclude.length > 0) {
|
|
67
|
+
for (const exc of config.exclude) {
|
|
68
|
+
args.push('--exclude', exc);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
args.push(workspace);
|
|
72
|
+
const { stdout } = await execFileAsync(binary, args, { timeout, maxBuffer: 50 * 1024 * 1024 });
|
|
73
|
+
let raw;
|
|
74
|
+
try {
|
|
75
|
+
raw = JSON.parse(stdout);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
throw new Error(`Failed to parse Semgrep JSON output: ${stdout.slice(0, 500)}`);
|
|
79
|
+
}
|
|
80
|
+
return (0, semgrep_1.normalizeSemgrepOutput)(raw);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Import Semgrep findings from a pre-generated JSON report.
|
|
84
|
+
*/
|
|
85
|
+
function importFromFile(reportPath) {
|
|
86
|
+
const resolved = path.resolve(reportPath);
|
|
87
|
+
if (!fs.existsSync(resolved)) {
|
|
88
|
+
throw new Error(`Semgrep report file not found: ${resolved}`);
|
|
89
|
+
}
|
|
90
|
+
const content = fs.readFileSync(resolved, 'utf-8');
|
|
91
|
+
let raw;
|
|
92
|
+
try {
|
|
93
|
+
raw = JSON.parse(content);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
throw new Error(`Failed to parse Semgrep report file: ${resolved}`);
|
|
97
|
+
}
|
|
98
|
+
return (0, semgrep_1.normalizeSemgrepOutput)(raw);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Run the Semgrep scanner according to the given configuration.
|
|
102
|
+
*/
|
|
103
|
+
async function runSemgrep(config, workspace = '.') {
|
|
104
|
+
if (!config.enabled || config.mode === 'disabled') {
|
|
105
|
+
return { scanner: 'semgrep', findings: [], success: true };
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
let findings;
|
|
109
|
+
if (config.mode === 'import') {
|
|
110
|
+
if (!config.reportPath) {
|
|
111
|
+
throw new Error('Semgrep import mode requires reportPath to be set');
|
|
112
|
+
}
|
|
113
|
+
findings = importFromFile(config.reportPath);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
// embedded or hybrid: run the binary
|
|
117
|
+
findings = await runEmbedded(config, workspace);
|
|
118
|
+
}
|
|
119
|
+
return { scanner: 'semgrep', findings, success: true };
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
123
|
+
return { scanner: 'semgrep', findings: [], success: false, error };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { TrivyScannerConfig, ScannerResult } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Run the Trivy scanner according to the given configuration.
|
|
4
|
+
*/
|
|
5
|
+
export declare function runTrivy(config: TrivyScannerConfig, workspace?: string): Promise<ScannerResult>;
|
|
6
|
+
//# sourceMappingURL=trivy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trivy.d.ts","sourceRoot":"","sources":["../../../../src/security/scanners/trivy.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,kBAAkB,EAAmB,aAAa,EAAE,MAAM,UAAU,CAAC;AAuD9E;;GAEG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,kBAAkB,EAC1B,SAAS,GAAE,MAAY,GACtB,OAAO,CAAC,aAAa,CAAC,CAsBxB"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runTrivy = runTrivy;
|
|
37
|
+
/**
|
|
38
|
+
* Trivy scanner integration.
|
|
39
|
+
* Supports embedded (binary) and import (pre-generated JSON) modes.
|
|
40
|
+
*/
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const child_process_1 = require("child_process");
|
|
44
|
+
const util_1 = require("util");
|
|
45
|
+
const trivy_1 = require("../normalizers/trivy");
|
|
46
|
+
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
47
|
+
/**
|
|
48
|
+
* Run Trivy in embedded mode.
|
|
49
|
+
* Invokes the `trivy` binary and parses its JSON output.
|
|
50
|
+
*/
|
|
51
|
+
async function runEmbedded(config, workspace) {
|
|
52
|
+
var _a, _b, _c, _d;
|
|
53
|
+
const binary = (_a = config.binaryPath) !== null && _a !== void 0 ? _a : 'trivy';
|
|
54
|
+
const scanMode = (_b = config.scanMode) !== null && _b !== void 0 ? _b : 'fs';
|
|
55
|
+
const scanners = (_c = config.scanners) !== null && _c !== void 0 ? _c : ['vuln', 'secret'];
|
|
56
|
+
const timeout = ((_d = config.timeout) !== null && _d !== void 0 ? _d : 120) * 1000;
|
|
57
|
+
const args = [
|
|
58
|
+
scanMode,
|
|
59
|
+
'--format', 'json',
|
|
60
|
+
'--scanners', scanners.join(','),
|
|
61
|
+
workspace,
|
|
62
|
+
];
|
|
63
|
+
const { stdout } = await execFileAsync(binary, args, { timeout, maxBuffer: 50 * 1024 * 1024 });
|
|
64
|
+
let raw;
|
|
65
|
+
try {
|
|
66
|
+
raw = JSON.parse(stdout);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
throw new Error(`Failed to parse Trivy JSON output: ${stdout.slice(0, 500)}`);
|
|
70
|
+
}
|
|
71
|
+
return (0, trivy_1.normalizeTrivyOutput)(raw);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Import Trivy findings from a pre-generated JSON report.
|
|
75
|
+
*/
|
|
76
|
+
function importFromFile(reportPath) {
|
|
77
|
+
const resolved = path.resolve(reportPath);
|
|
78
|
+
if (!fs.existsSync(resolved)) {
|
|
79
|
+
throw new Error(`Trivy report file not found: ${resolved}`);
|
|
80
|
+
}
|
|
81
|
+
const content = fs.readFileSync(resolved, 'utf-8');
|
|
82
|
+
let raw;
|
|
83
|
+
try {
|
|
84
|
+
raw = JSON.parse(content);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
throw new Error(`Failed to parse Trivy report file: ${resolved}`);
|
|
88
|
+
}
|
|
89
|
+
return (0, trivy_1.normalizeTrivyOutput)(raw);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Run the Trivy scanner according to the given configuration.
|
|
93
|
+
*/
|
|
94
|
+
async function runTrivy(config, workspace = '.') {
|
|
95
|
+
if (!config.enabled || config.mode === 'disabled') {
|
|
96
|
+
return { scanner: 'trivy', findings: [], success: true };
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
let findings;
|
|
100
|
+
if (config.mode === 'import') {
|
|
101
|
+
if (!config.reportPath) {
|
|
102
|
+
throw new Error('Trivy import mode requires reportPath to be set');
|
|
103
|
+
}
|
|
104
|
+
findings = importFromFile(config.reportPath);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
findings = await runEmbedded(config, workspace);
|
|
108
|
+
}
|
|
109
|
+
return { scanner: 'trivy', findings, success: true };
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
113
|
+
return { scanner: 'trivy', findings: [], success: false, error };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zap.d.ts","sourceRoot":"","sources":["../../../../src/security/scanners/zap.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,gBAAgB,EAAmB,aAAa,EAAE,MAAM,UAAU,CAAC;AA+E5E;;GAEG;AACH,wBAAsB,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAsB7E"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runZap = runZap;
|
|
37
|
+
/**
|
|
38
|
+
* OWASP ZAP scanner integration.
|
|
39
|
+
* Supports import (pre-generated JSON) and embedded (binary) modes.
|
|
40
|
+
*/
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const child_process_1 = require("child_process");
|
|
44
|
+
const util_1 = require("util");
|
|
45
|
+
const zap_1 = require("../normalizers/zap");
|
|
46
|
+
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
47
|
+
/**
|
|
48
|
+
* Run ZAP in embedded mode using the baseline scan script.
|
|
49
|
+
*/
|
|
50
|
+
async function runEmbedded(config) {
|
|
51
|
+
var _a;
|
|
52
|
+
if (!config.targetUrl) {
|
|
53
|
+
throw new Error('ZAP embedded mode requires targetUrl to be set');
|
|
54
|
+
}
|
|
55
|
+
const timeout = ((_a = config.timeout) !== null && _a !== void 0 ? _a : 300) * 1000;
|
|
56
|
+
const reportFile = path.join(process.cwd(), 'reports', 'zap-raw.json');
|
|
57
|
+
// Ensure reports directory exists
|
|
58
|
+
const reportsDir = path.dirname(reportFile);
|
|
59
|
+
if (!fs.existsSync(reportsDir)) {
|
|
60
|
+
fs.mkdirSync(reportsDir, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
// Run zap-baseline.py with parameterized arguments (no shell interpolation)
|
|
63
|
+
let ranSuccessfully = false;
|
|
64
|
+
try {
|
|
65
|
+
await execFileAsync('zap-baseline.py', ['-t', config.targetUrl, '-J', reportFile], { timeout, maxBuffer: 10 * 1024 * 1024 });
|
|
66
|
+
ranSuccessfully = true;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// zap-baseline.py may exit with non-zero even on success; check the output file
|
|
70
|
+
ranSuccessfully = fs.existsSync(reportFile);
|
|
71
|
+
}
|
|
72
|
+
if (!ranSuccessfully) {
|
|
73
|
+
// Try zap.sh as fallback (also parameterized, no shell interpolation)
|
|
74
|
+
try {
|
|
75
|
+
await execFileAsync('zap.sh', ['-cmd', '-quickurl', config.targetUrl, '-quickout', reportFile, '-quickprogress'], { timeout, maxBuffer: 10 * 1024 * 1024 });
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
if (!fs.existsSync(reportFile)) {
|
|
79
|
+
throw new Error(`ZAP embedded scan failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const content = fs.readFileSync(reportFile, 'utf-8');
|
|
84
|
+
let raw;
|
|
85
|
+
try {
|
|
86
|
+
raw = JSON.parse(content);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
throw new Error(`Failed to parse ZAP JSON output from ${reportFile}`);
|
|
90
|
+
}
|
|
91
|
+
return (0, zap_1.normalizeZapOutput)(raw);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Import ZAP findings from a pre-generated JSON report.
|
|
95
|
+
*/
|
|
96
|
+
function importFromFile(reportPath) {
|
|
97
|
+
const resolved = path.resolve(reportPath);
|
|
98
|
+
if (!fs.existsSync(resolved)) {
|
|
99
|
+
throw new Error(`ZAP report file not found: ${resolved}`);
|
|
100
|
+
}
|
|
101
|
+
const content = fs.readFileSync(resolved, 'utf-8');
|
|
102
|
+
let raw;
|
|
103
|
+
try {
|
|
104
|
+
raw = JSON.parse(content);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
throw new Error(`Failed to parse ZAP report file: ${resolved}`);
|
|
108
|
+
}
|
|
109
|
+
return (0, zap_1.normalizeZapOutput)(raw);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Run the ZAP scanner according to the given configuration.
|
|
113
|
+
*/
|
|
114
|
+
async function runZap(config) {
|
|
115
|
+
if (!config.enabled || config.mode === 'disabled') {
|
|
116
|
+
return { scanner: 'zap', findings: [], success: true };
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
let findings;
|
|
120
|
+
if (config.mode === 'import') {
|
|
121
|
+
if (!config.reportPath) {
|
|
122
|
+
throw new Error('ZAP import mode requires reportPath to be set');
|
|
123
|
+
}
|
|
124
|
+
findings = importFromFile(config.reportPath);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
findings = await runEmbedded(config);
|
|
128
|
+
}
|
|
129
|
+
return { scanner: 'zap', findings, success: true };
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
133
|
+
return { scanner: 'zap', findings: [], success: false, error };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalized security finding model.
|
|
3
|
+
* All scanner outputs (Semgrep, Trivy, ZAP, etc.) are mapped to this common schema.
|
|
4
|
+
*/
|
|
5
|
+
export type ScannerName = 'semgrep' | 'trivy' | 'zap' | 'gitleaks' | 'other';
|
|
6
|
+
export type FindingCategory = 'sast' | 'sca' | 'secret' | 'misconfig' | 'dast' | 'auth' | 'injection' | 'data-exposure' | 'crypto' | 'unknown';
|
|
7
|
+
export type FindingSeverity = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
|
|
8
|
+
export interface SecurityFinding {
|
|
9
|
+
scanner: ScannerName;
|
|
10
|
+
category: FindingCategory;
|
|
11
|
+
severity: FindingSeverity;
|
|
12
|
+
title: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
ruleId?: string;
|
|
15
|
+
cwe?: string[];
|
|
16
|
+
cve?: string[];
|
|
17
|
+
owasp?: string[];
|
|
18
|
+
filePath?: string;
|
|
19
|
+
lineStart?: number;
|
|
20
|
+
lineEnd?: number;
|
|
21
|
+
endpoint?: {
|
|
22
|
+
method?: string;
|
|
23
|
+
path?: string;
|
|
24
|
+
};
|
|
25
|
+
packageName?: string;
|
|
26
|
+
installedVersion?: string;
|
|
27
|
+
fixedVersion?: string;
|
|
28
|
+
secretType?: string;
|
|
29
|
+
scannerNativePayload?: unknown;
|
|
30
|
+
}
|
|
31
|
+
export type ScannerMode = 'embedded' | 'import' | 'disabled';
|
|
32
|
+
export interface SemgrepScannerConfig {
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
mode: ScannerMode;
|
|
35
|
+
/** Semgrep config (e.g. "p/default", "p/security-audit", or path to custom rules) */
|
|
36
|
+
config?: string;
|
|
37
|
+
/** Binary path override */
|
|
38
|
+
binaryPath?: string;
|
|
39
|
+
/** Include globs */
|
|
40
|
+
include?: string[];
|
|
41
|
+
/** Exclude globs */
|
|
42
|
+
exclude?: string[];
|
|
43
|
+
/** Timeout in seconds */
|
|
44
|
+
timeout?: number;
|
|
45
|
+
/** Path to pre-generated Semgrep JSON report (import mode) */
|
|
46
|
+
reportPath?: string;
|
|
47
|
+
}
|
|
48
|
+
export interface TrivyScannerConfig {
|
|
49
|
+
enabled: boolean;
|
|
50
|
+
mode: ScannerMode;
|
|
51
|
+
/** Scan mode: 'fs' (filesystem) or 'repo' */
|
|
52
|
+
scanMode?: 'fs' | 'repo';
|
|
53
|
+
/** What to scan: combinations of 'vuln', 'misconfig', 'secret' */
|
|
54
|
+
scanners?: Array<'vuln' | 'misconfig' | 'secret'>;
|
|
55
|
+
/** Binary path override */
|
|
56
|
+
binaryPath?: string;
|
|
57
|
+
/** Timeout in seconds */
|
|
58
|
+
timeout?: number;
|
|
59
|
+
/** Path to pre-generated Trivy JSON report (import mode) */
|
|
60
|
+
reportPath?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface ZapScannerConfig {
|
|
63
|
+
enabled: boolean;
|
|
64
|
+
mode: ScannerMode;
|
|
65
|
+
/** Base URL for dynamic scanning */
|
|
66
|
+
targetUrl?: string;
|
|
67
|
+
/** Scan profile */
|
|
68
|
+
profile?: 'baseline' | 'full';
|
|
69
|
+
/** Authentication configuration */
|
|
70
|
+
auth?: {
|
|
71
|
+
loginUrl?: string;
|
|
72
|
+
username?: string;
|
|
73
|
+
password?: string;
|
|
74
|
+
tokenHeader?: string;
|
|
75
|
+
tokenValue?: string;
|
|
76
|
+
};
|
|
77
|
+
/** Timeout in seconds */
|
|
78
|
+
timeout?: number;
|
|
79
|
+
/** Path to pre-generated ZAP JSON/XML report (import mode) */
|
|
80
|
+
reportPath?: string;
|
|
81
|
+
}
|
|
82
|
+
export interface SecurityScannerConfigs {
|
|
83
|
+
semgrep?: SemgrepScannerConfig;
|
|
84
|
+
trivy?: TrivyScannerConfig;
|
|
85
|
+
zap?: ZapScannerConfig;
|
|
86
|
+
}
|
|
87
|
+
export interface SecurityGateConfig {
|
|
88
|
+
/** Fail if any CRITICAL finding exists */
|
|
89
|
+
failOnCritical?: boolean;
|
|
90
|
+
/** Fail if any HIGH finding exists */
|
|
91
|
+
failOnHigh?: boolean;
|
|
92
|
+
/** Maximum allowed MEDIUM findings */
|
|
93
|
+
maxMedium?: number;
|
|
94
|
+
/** Maximum allowed LOW findings */
|
|
95
|
+
maxLow?: number;
|
|
96
|
+
/** Maximum allowed secrets (any severity) */
|
|
97
|
+
maxSecrets?: number;
|
|
98
|
+
/** Maximum allowed HIGH misconfigurations */
|
|
99
|
+
maxMisconfigHigh?: number;
|
|
100
|
+
/** Maximum allowed CRITICAL vulnerabilities */
|
|
101
|
+
maxCriticalVulns?: number;
|
|
102
|
+
/** Maximum allowed HIGH vulnerabilities */
|
|
103
|
+
maxHighVulns?: number;
|
|
104
|
+
}
|
|
105
|
+
export interface SecurityScanConfig {
|
|
106
|
+
enabled: boolean;
|
|
107
|
+
/** Workspace directory to scan. Default: '.' */
|
|
108
|
+
workspace?: string;
|
|
109
|
+
scanners?: SecurityScannerConfigs;
|
|
110
|
+
gate?: SecurityGateConfig;
|
|
111
|
+
}
|
|
112
|
+
export interface ScannerResult {
|
|
113
|
+
scanner: ScannerName;
|
|
114
|
+
findings: SecurityFinding[];
|
|
115
|
+
/** Whether the scanner ran successfully */
|
|
116
|
+
success: boolean;
|
|
117
|
+
/** Error message if the scanner failed */
|
|
118
|
+
error?: string;
|
|
119
|
+
/** Raw output or metadata from the scanner */
|
|
120
|
+
metadata?: Record<string, unknown>;
|
|
121
|
+
}
|
|
122
|
+
export interface SecurityScanSummary {
|
|
123
|
+
scannersRun: ScannerName[];
|
|
124
|
+
totalFindings: number;
|
|
125
|
+
bySeverity: Record<FindingSeverity, number>;
|
|
126
|
+
byCategory: Record<FindingCategory, number>;
|
|
127
|
+
byScanner: Record<ScannerName, number>;
|
|
128
|
+
findings: SecurityFinding[];
|
|
129
|
+
gateResult?: SecurityGateResult;
|
|
130
|
+
}
|
|
131
|
+
export interface SecurityGateResult {
|
|
132
|
+
passed: boolean;
|
|
133
|
+
reasons: string[];
|
|
134
|
+
thresholds: SecurityGateConfig;
|
|
135
|
+
counts: {
|
|
136
|
+
critical: number;
|
|
137
|
+
high: number;
|
|
138
|
+
medium: number;
|
|
139
|
+
low: number;
|
|
140
|
+
secrets: number;
|
|
141
|
+
misconfigHigh: number;
|
|
142
|
+
criticalVulns: number;
|
|
143
|
+
highVulns: number;
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=types.d.ts.map
|