@contrast/contrast 1.0.3 → 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.
- package/.prettierignore +1 -0
- package/README.md +20 -14
- package/dist/audit/languageAnalysisEngine/{langugageAnalysisFactory.js → languageAnalysisFactory.js} +2 -12
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +62 -234
- package/dist/audit/languageAnalysisEngine/report/models/reportLibraryModel.js +19 -0
- package/dist/audit/languageAnalysisEngine/report/models/reportListModel.js +24 -0
- package/dist/audit/languageAnalysisEngine/report/models/reportSeverityModel.js +10 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +24 -129
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +85 -0
- package/dist/audit/languageAnalysisEngine/sendSnapshot.js +3 -1
- package/dist/commands/audit/auditController.js +6 -3
- package/dist/commands/scan/processScan.js +4 -3
- package/dist/common/HTTPClient.js +19 -26
- package/dist/common/versionChecker.js +14 -12
- package/dist/constants/constants.js +1 -1
- package/dist/constants/lambda.js +3 -1
- package/dist/constants/locales.js +17 -10
- package/dist/constants.js +5 -1
- package/dist/index.js +2 -2
- package/dist/lambda/help.js +22 -14
- package/dist/lambda/lambda.js +6 -0
- package/dist/scan/models/groupedResultsModel.js +10 -0
- package/dist/scan/models/resultContentModel.js +2 -0
- package/dist/scan/models/scanResultsModel.js +11 -0
- package/dist/scan/scan.js +90 -95
- package/dist/scan/scanConfig.js +1 -1
- package/dist/utils/getConfig.js +3 -0
- package/package.json +2 -2
- package/src/audit/languageAnalysisEngine/{langugageAnalysisFactory.js → languageAnalysisFactory.js} +2 -16
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +127 -0
- package/src/audit/languageAnalysisEngine/report/models/reportLibraryModel.ts +30 -0
- package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +32 -0
- package/src/audit/languageAnalysisEngine/report/models/reportSeverityModel.ts +9 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +56 -0
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +110 -0
- package/src/audit/languageAnalysisEngine/sendSnapshot.js +3 -1
- package/src/commands/audit/auditController.ts +12 -3
- package/src/commands/scan/processScan.js +4 -6
- package/src/common/HTTPClient.js +31 -38
- package/src/common/errorHandling.ts +0 -1
- package/src/common/versionChecker.ts +24 -22
- package/src/constants/constants.js +1 -1
- package/src/constants/lambda.js +3 -1
- package/src/constants/locales.js +20 -10
- package/src/constants.js +7 -1
- package/src/index.ts +2 -3
- package/src/lambda/help.ts +22 -14
- package/src/lambda/lambda.ts +8 -0
- package/src/scan/models/groupedResultsModel.ts +18 -0
- package/src/scan/models/resultContentModel.ts +86 -0
- package/src/scan/models/scanResultsModel.ts +52 -0
- package/src/scan/scan.ts +192 -0
- package/src/scan/scanConfig.js +1 -1
- package/src/scan/scanController.js +2 -0
- package/src/utils/getConfig.ts +10 -0
- package/dist/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +0 -17
- package/dist/audit/languageAnalysisEngine/report/newReportingFeature.js +0 -81
- package/src/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +0 -27
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.js +0 -303
- package/src/audit/languageAnalysisEngine/report/newReportingFeature.js +0 -124
- package/src/audit/languageAnalysisEngine/report/reportingFeature.js +0 -190
- package/src/scan/scan.js +0 -195
package/dist/scan/scan.js
CHANGED
|
@@ -1,44 +1,43 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.stripMustacheTags = exports.getMessage = exports.getGroups = exports.formatLinks = exports.formatScanOutput = exports.sendScan = exports.isFileAllowed = exports.allowedFileTypes = void 0;
|
|
7
|
+
const commonApi_js_1 = __importDefault(require("../utils/commonApi.js"));
|
|
8
|
+
const fileUtils_1 = __importDefault(require("../scan/fileUtils"));
|
|
9
|
+
const i18n_1 = __importDefault(require("i18n"));
|
|
10
|
+
const oraWrapper_1 = __importDefault(require("../utils/oraWrapper"));
|
|
11
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
+
const groupedResultsModel_1 = require("./models/groupedResultsModel");
|
|
13
|
+
exports.allowedFileTypes = ['.jar', '.war', '.js', '.zip', '.exe'];
|
|
14
|
+
const isFileAllowed = (scanOption) => {
|
|
9
15
|
let valid = false;
|
|
10
|
-
allowedFileTypes.forEach(fileType => {
|
|
16
|
+
exports.allowedFileTypes.forEach(fileType => {
|
|
11
17
|
if (scanOption.endsWith(fileType)) {
|
|
12
18
|
valid = true;
|
|
13
19
|
}
|
|
14
20
|
});
|
|
15
21
|
return valid;
|
|
16
22
|
};
|
|
17
|
-
|
|
18
|
-
return oldString
|
|
19
|
-
.replace(/\n/g, ' ')
|
|
20
|
-
.replace(/{{.*?}}/g, '\n')
|
|
21
|
-
.replace(/\$\$LINK_DELIM\$\$/g, '\n')
|
|
22
|
-
.replace(/\s+/g, ' ')
|
|
23
|
-
.trim();
|
|
24
|
-
};
|
|
23
|
+
exports.isFileAllowed = isFileAllowed;
|
|
25
24
|
const sendScan = async (config) => {
|
|
26
|
-
if (!isFileAllowed(config.file)) {
|
|
27
|
-
console.log(
|
|
25
|
+
if (!(0, exports.isFileAllowed)(config.file)) {
|
|
26
|
+
console.log(i18n_1.default.__('scanErrorFileMessage'));
|
|
28
27
|
process.exit(9);
|
|
29
28
|
}
|
|
30
29
|
else {
|
|
31
|
-
|
|
32
|
-
const client =
|
|
33
|
-
const startUploadSpinner =
|
|
34
|
-
|
|
30
|
+
fileUtils_1.default.checkFilePermissions(config.file);
|
|
31
|
+
const client = commonApi_js_1.default.getHttpClient(config);
|
|
32
|
+
const startUploadSpinner = oraWrapper_1.default.returnOra(i18n_1.default.__('uploadingScan'));
|
|
33
|
+
oraWrapper_1.default.startSpinner(startUploadSpinner);
|
|
35
34
|
return await client
|
|
36
35
|
.sendArtifact(config)
|
|
37
36
|
.then(res => {
|
|
38
37
|
if (res.statusCode === 201) {
|
|
39
|
-
|
|
38
|
+
oraWrapper_1.default.succeedSpinner(startUploadSpinner, i18n_1.default.__('uploadingScanSuccessful'));
|
|
40
39
|
if (config.verbose) {
|
|
41
|
-
console.log(
|
|
40
|
+
console.log(i18n_1.default.__('responseMessage', res.body));
|
|
42
41
|
}
|
|
43
42
|
return res.body.id;
|
|
44
43
|
}
|
|
@@ -47,12 +46,12 @@ const sendScan = async (config) => {
|
|
|
47
46
|
console.log(res.statusCode);
|
|
48
47
|
console.log(config);
|
|
49
48
|
}
|
|
50
|
-
|
|
49
|
+
oraWrapper_1.default.failSpinner(startUploadSpinner, i18n_1.default.__('uploadingScanFail'));
|
|
51
50
|
if (res.statusCode === 403) {
|
|
52
|
-
console.log(
|
|
51
|
+
console.log(i18n_1.default.__('permissionsError'));
|
|
53
52
|
process.exit(1);
|
|
54
53
|
}
|
|
55
|
-
console.log(
|
|
54
|
+
console.log(i18n_1.default.__('genericServiceError', res.statusCode));
|
|
56
55
|
process.exit(1);
|
|
57
56
|
}
|
|
58
57
|
})
|
|
@@ -61,101 +60,97 @@ const sendScan = async (config) => {
|
|
|
61
60
|
});
|
|
62
61
|
}
|
|
63
62
|
};
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
exports.sendScan = sendScan;
|
|
64
|
+
function formatScanOutput(scanResults) {
|
|
65
|
+
const { projectOverview, scanResultsInstances } = scanResults;
|
|
66
|
+
if (scanResultsInstances.content.length === 0) {
|
|
67
|
+
console.log(i18n_1.default.__('scanNoVulnerabilitiesFound'));
|
|
68
68
|
}
|
|
69
69
|
else {
|
|
70
|
-
|
|
70
|
+
const message = projectOverview.critical || projectOverview.high
|
|
71
71
|
? 'Here are your top priorities to fix'
|
|
72
72
|
: "No major issues, here's what we found";
|
|
73
|
-
console.log(
|
|
73
|
+
console.log(chalk_1.default.bold(message));
|
|
74
74
|
console.log();
|
|
75
|
-
const groups = getGroups(
|
|
75
|
+
const groups = getGroups(scanResultsInstances.content);
|
|
76
76
|
groups.forEach(entry => {
|
|
77
|
-
console.log(
|
|
77
|
+
console.log(chalk_1.default.bold(`[ ${entry.severity} ] | ${entry.ruleId} (${entry.lineInfoSet.size}) - ` +
|
|
78
|
+
`${entry.message}`));
|
|
78
79
|
let count = 1;
|
|
79
80
|
entry.lineInfoSet.forEach(lineInfo => {
|
|
80
81
|
console.log(`\t ${count}. ${lineInfo}`);
|
|
81
82
|
count++;
|
|
82
83
|
});
|
|
83
|
-
if (entry?.
|
|
84
|
-
|
|
84
|
+
if (entry?.issue) {
|
|
85
|
+
console.log(chalk_1.default.bold('Issue' + ': ') + entry.issue);
|
|
85
86
|
}
|
|
86
|
-
if (entry?.
|
|
87
|
-
|
|
87
|
+
if (entry?.advice) {
|
|
88
|
+
console.log(chalk_1.default.bold('Advice' + ': ') + entry.advice);
|
|
88
89
|
}
|
|
89
|
-
if (entry?.
|
|
90
|
-
formatLinks('
|
|
90
|
+
if (entry?.learn && entry?.learn.length > 0) {
|
|
91
|
+
formatLinks('Learn', entry.learn);
|
|
91
92
|
}
|
|
92
|
-
console.log(chalk.bold('How to fix:'));
|
|
93
|
-
console.log(entry.recommendation);
|
|
94
93
|
console.log();
|
|
95
94
|
});
|
|
96
|
-
|
|
97
|
-
overview.high +
|
|
98
|
-
overview.medium +
|
|
99
|
-
overview.low +
|
|
100
|
-
overview.note;
|
|
101
|
-
let vulMessage = totalVulnerabilities === 1 ? `vulnerability` : `vulnerabilities`;
|
|
102
|
-
console.log(chalk.bold(`Found ${totalVulnerabilities} ${vulMessage}`));
|
|
103
|
-
console.log(i18n.__('foundDetailedVulnerabilities', overview.critical, overview.high, overview.medium, overview.low, overview.note));
|
|
95
|
+
printVulnInfo(projectOverview);
|
|
104
96
|
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
97
|
+
}
|
|
98
|
+
exports.formatScanOutput = formatScanOutput;
|
|
99
|
+
function printVulnInfo(projectOverview) {
|
|
100
|
+
const totalVulnerabilities = getTotalVulns(projectOverview);
|
|
101
|
+
const vulMessage = totalVulnerabilities === 1 ? `vulnerability` : `vulnerabilities`;
|
|
102
|
+
console.log(chalk_1.default.bold(`Found ${totalVulnerabilities} ${vulMessage}`));
|
|
103
|
+
console.log(i18n_1.default.__('foundDetailedVulnerabilities', String(projectOverview.critical), String(projectOverview.high), String(projectOverview.medium), String(projectOverview.low), String(projectOverview.note)));
|
|
104
|
+
}
|
|
105
|
+
function getTotalVulns(projectOverview) {
|
|
106
|
+
return (projectOverview.critical +
|
|
107
|
+
projectOverview.high +
|
|
108
|
+
projectOverview.medium +
|
|
109
|
+
projectOverview.low +
|
|
110
|
+
projectOverview.note);
|
|
111
|
+
}
|
|
112
|
+
function formatLinks(objName, entry) {
|
|
113
|
+
console.log(chalk_1.default.bold(objName + ':'));
|
|
108
114
|
entry.forEach(link => {
|
|
109
115
|
console.log(link);
|
|
110
116
|
});
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
}
|
|
118
|
+
exports.formatLinks = formatLinks;
|
|
119
|
+
function getGroups(content) {
|
|
114
120
|
const groupTypeSet = new Set(content.map(({ ruleId }) => ruleId));
|
|
115
|
-
|
|
121
|
+
const groupTypeResults = [];
|
|
116
122
|
groupTypeSet.forEach(groupName => {
|
|
117
|
-
|
|
118
|
-
ruleId: groupName,
|
|
119
|
-
lineInfoSet: new Set(),
|
|
120
|
-
cwe: '',
|
|
121
|
-
owasp: '',
|
|
122
|
-
reference: '',
|
|
123
|
-
recommendation: '',
|
|
124
|
-
severity: ''
|
|
125
|
-
};
|
|
123
|
+
const groupResultsObj = new groupedResultsModel_1.GroupedResultsModel(groupName);
|
|
126
124
|
content.forEach(resultEntry => {
|
|
127
125
|
if (resultEntry.ruleId === groupName) {
|
|
128
126
|
groupResultsObj.severity = resultEntry.severity;
|
|
129
|
-
groupResultsObj.
|
|
130
|
-
groupResultsObj.
|
|
131
|
-
groupResultsObj.
|
|
132
|
-
groupResultsObj.
|
|
133
|
-
|
|
134
|
-
: 'No Recommendations Data Found';
|
|
135
|
-
groupResultsObj.lineInfoSet.add(formattedCodeLine(resultEntry));
|
|
127
|
+
groupResultsObj.issue = stripMustacheTags(resultEntry.issue);
|
|
128
|
+
groupResultsObj.advice = resultEntry.advice;
|
|
129
|
+
groupResultsObj.learn = resultEntry.learn;
|
|
130
|
+
groupResultsObj.message = resultEntry.message?.text;
|
|
131
|
+
groupResultsObj.lineInfoSet.add(getMessage(resultEntry.locations));
|
|
136
132
|
}
|
|
137
133
|
});
|
|
138
134
|
groupTypeResults.push(groupResultsObj);
|
|
139
135
|
});
|
|
140
136
|
return groupTypeResults;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
};
|
|
137
|
+
}
|
|
138
|
+
exports.getGroups = getGroups;
|
|
139
|
+
function getMessage(locations) {
|
|
140
|
+
const message = locations[0]?.physicalLocation?.artifactLocation?.uri || '';
|
|
141
|
+
const lineNumber = locations[0]?.physicalLocation?.region?.startLine || '';
|
|
142
|
+
if (!lineNumber) {
|
|
143
|
+
return '@' + message;
|
|
144
|
+
}
|
|
145
|
+
return '@' + message + ':' + lineNumber;
|
|
146
|
+
}
|
|
147
|
+
exports.getMessage = getMessage;
|
|
148
|
+
function stripMustacheTags(oldString) {
|
|
149
|
+
return oldString
|
|
150
|
+
.replace(/\n/g, ' ')
|
|
151
|
+
.replace(/{{.*?}}/g, '\n')
|
|
152
|
+
.replace(/\$\$LINK_DELIM\$\$/g, '\n')
|
|
153
|
+
.replace(/\s+/g, ' ')
|
|
154
|
+
.trim();
|
|
155
|
+
}
|
|
156
|
+
exports.stripMustacheTags = stripMustacheTags;
|
package/dist/scan/scanConfig.js
CHANGED
|
@@ -18,7 +18,7 @@ const getScanConfig = argv => {
|
|
|
18
18
|
if (!Object.values(supportedLanguages).includes(scanParams.language)) {
|
|
19
19
|
console.log(`Did not recognise --language ${scanParams.language}`);
|
|
20
20
|
console.log(i18n.__('constantsHowToRunDev3'));
|
|
21
|
-
process.exit(
|
|
21
|
+
process.exit(1);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
if (!scanParams.name && scanParams.file) {
|
package/dist/utils/getConfig.js
CHANGED
|
@@ -10,6 +10,9 @@ const localConfig = (name, version) => {
|
|
|
10
10
|
configName: name
|
|
11
11
|
});
|
|
12
12
|
config.set('version', version);
|
|
13
|
+
if (process.env.CONTRAST_CODSEC_DISABLE_UPDATE_MESSAGE) {
|
|
14
|
+
config.set('updateMessageHidden', JSON.parse(process.env.CONTRAST_CODSEC_DISABLE_UPDATE_MESSAGE.toLowerCase()));
|
|
15
|
+
}
|
|
13
16
|
if (!config.has('host')) {
|
|
14
17
|
config.set('host', 'https://ce.contrastsecurity.com/');
|
|
15
18
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/contrast",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Contrast Security's command line tool",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"dev": "npx ts-node src/index.ts"
|
|
36
36
|
},
|
|
37
37
|
"engines": {
|
|
38
|
-
"node": ">=16
|
|
38
|
+
"node": ">=16"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@aws-sdk/client-iam": "^3.78.0",
|
package/src/audit/languageAnalysisEngine/{langugageAnalysisFactory.js → languageAnalysisFactory.js}
RENAMED
|
@@ -10,8 +10,6 @@ const pythonAE = require('../pythonAnalysisEngine')
|
|
|
10
10
|
const phpAE = require('../phpAnalysisEngine')
|
|
11
11
|
const goAE = require('../goAnalysisEngine')
|
|
12
12
|
const { vulnerabilityReport } = require('./report/reportingFeature')
|
|
13
|
-
const { vulnReportWithoutDevDep } = require('./report/newReportingFeature')
|
|
14
|
-
const { checkDevDeps } = require('./report/checkIgnoreDevDep')
|
|
15
13
|
const { newSendSnapShot } = require('../languageAnalysisEngine/sendSnapshot')
|
|
16
14
|
const fs = require('fs')
|
|
17
15
|
const chalk = require('chalk')
|
|
@@ -50,19 +48,7 @@ module.exports = exports = (err, analysis) => {
|
|
|
50
48
|
console.log('\n **************CONTRAST OSS ANALYSIS BEGINS**************')
|
|
51
49
|
const snapshotResponse = await newSendSnapShot(analysis, catalogueAppId)
|
|
52
50
|
|
|
53
|
-
|
|
54
|
-
const ignoreDevUrl = await checkDevDeps(config)
|
|
55
|
-
if (ignoreDevUrl) {
|
|
56
|
-
await vulnReportWithoutDevDep(
|
|
57
|
-
analysis,
|
|
58
|
-
catalogueAppId,
|
|
59
|
-
snapshotResponse.id,
|
|
60
|
-
config
|
|
61
|
-
)
|
|
62
|
-
} else {
|
|
63
|
-
await vulnerabilityReport(analysis, catalogueAppId, config)
|
|
64
|
-
}
|
|
65
|
-
}
|
|
51
|
+
await vulnerabilityReport(analysis, catalogueAppId, snapshotResponse.id)
|
|
66
52
|
|
|
67
53
|
//should be moved to processAudit.ts once promises implemented
|
|
68
54
|
await auditSave(config)
|
|
@@ -120,7 +106,7 @@ async function auditSave(config) {
|
|
|
120
106
|
} else {
|
|
121
107
|
console.log(i18n.__('auditBadFiletypeSpecifiedForSave'))
|
|
122
108
|
}
|
|
123
|
-
} else {
|
|
109
|
+
} else if (config.save === null) {
|
|
124
110
|
console.log(i18n.__('auditNoFiletypeSpecifiedForSave'))
|
|
125
111
|
}
|
|
126
112
|
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import i18n from 'i18n'
|
|
2
|
+
import { getHttpClient, handleResponseErrors } from '../../../utils/commonApi'
|
|
3
|
+
import {
|
|
4
|
+
ReportCompositeKey,
|
|
5
|
+
ReportList,
|
|
6
|
+
ReportModelStructure
|
|
7
|
+
} from './models/reportListModel'
|
|
8
|
+
import { ReportSeverityModel } from './models/reportSeverityModel'
|
|
9
|
+
import { orderBy } from 'lodash'
|
|
10
|
+
import chalk from 'chalk'
|
|
11
|
+
import { ReportLibraryModel } from './models/reportLibraryModel'
|
|
12
|
+
import { findHighestSeverityCVE, findNameAndVersion } from './utils/reportUtils'
|
|
13
|
+
import {
|
|
14
|
+
failSpinner,
|
|
15
|
+
returnOra,
|
|
16
|
+
startSpinner,
|
|
17
|
+
succeedSpinner
|
|
18
|
+
} from '../../../utils/oraWrapper'
|
|
19
|
+
|
|
20
|
+
export const createLibraryHeader = (
|
|
21
|
+
id: string,
|
|
22
|
+
numberOfVulnerableLibraries: number,
|
|
23
|
+
numberOfCves: number,
|
|
24
|
+
name: string
|
|
25
|
+
) => {
|
|
26
|
+
name
|
|
27
|
+
? console.log(`\n Application Name: ${name} | Application ID: ${id}`)
|
|
28
|
+
: console.log(` Application ID: ${id}`)
|
|
29
|
+
|
|
30
|
+
numberOfVulnerableLibraries === 1
|
|
31
|
+
? console.log(
|
|
32
|
+
'\n **************************' +
|
|
33
|
+
` Found 1 vulnerable library containing ${numberOfCves} CVE's` +
|
|
34
|
+
'************************** '
|
|
35
|
+
)
|
|
36
|
+
: console.log(
|
|
37
|
+
'\n **************************' +
|
|
38
|
+
` Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVE's ` +
|
|
39
|
+
'************************** '
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const getReport = async (config: any, reportId: string) => {
|
|
44
|
+
const client = getHttpClient(config)
|
|
45
|
+
|
|
46
|
+
const reportSpinner = returnOra(i18n.__('auditReportWaiting'))
|
|
47
|
+
reportSpinner.indent = 1
|
|
48
|
+
startSpinner(reportSpinner)
|
|
49
|
+
return client
|
|
50
|
+
.getReportById(config, reportId)
|
|
51
|
+
.then((res: { statusCode: number; body: any }) => {
|
|
52
|
+
if (res.statusCode === 200) {
|
|
53
|
+
succeedSpinner(reportSpinner, i18n.__('auditReportSuccessMessage'))
|
|
54
|
+
return res.body
|
|
55
|
+
} else {
|
|
56
|
+
failSpinner(reportSpinner, i18n.__('auditReportFail'))
|
|
57
|
+
console.log('config-------------------')
|
|
58
|
+
console.log(config)
|
|
59
|
+
console.log('reportId----------------')
|
|
60
|
+
console.log(reportId)
|
|
61
|
+
console.log(JSON.stringify(res))
|
|
62
|
+
handleResponseErrors(res, 'report')
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
.catch((err: any) => {
|
|
66
|
+
console.log(err)
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const printVulnerabilityResponse = (
|
|
71
|
+
vulnerabilities: ReportLibraryModel[],
|
|
72
|
+
config: any
|
|
73
|
+
) => {
|
|
74
|
+
let hasSomeVulnerabilitiesReported = false
|
|
75
|
+
printFormattedOutput(vulnerabilities, config)
|
|
76
|
+
if (Object.keys(vulnerabilities).length > 0) {
|
|
77
|
+
hasSomeVulnerabilitiesReported = true
|
|
78
|
+
}
|
|
79
|
+
return hasSomeVulnerabilitiesReported
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const printFormattedOutput = (
|
|
83
|
+
libraries: ReportLibraryModel[],
|
|
84
|
+
config: any
|
|
85
|
+
) => {
|
|
86
|
+
const report = new ReportList()
|
|
87
|
+
|
|
88
|
+
for (const library of libraries) {
|
|
89
|
+
const { name, version } = findNameAndVersion(library, config)
|
|
90
|
+
|
|
91
|
+
const newOutputModel = new ReportModelStructure(
|
|
92
|
+
new ReportCompositeKey(
|
|
93
|
+
name,
|
|
94
|
+
version,
|
|
95
|
+
findHighestSeverityCVE(library.cveArray) as ReportSeverityModel
|
|
96
|
+
),
|
|
97
|
+
library.cveArray
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
report.reportOutputList.push(newOutputModel)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const orderedOutputList = orderBy(
|
|
104
|
+
report.reportOutputList,
|
|
105
|
+
reportListItem => reportListItem.compositeKey.highestSeverity.priority
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
for (const reportModel of orderedOutputList) {
|
|
109
|
+
const name = reportModel.compositeKey.libraryName
|
|
110
|
+
const version = reportModel.compositeKey.libraryVersion
|
|
111
|
+
const highestSeverity = reportModel.compositeKey.highestSeverity.severity
|
|
112
|
+
|
|
113
|
+
const numOfCVEs = reportModel.cveArray.length
|
|
114
|
+
|
|
115
|
+
const cveNames: string[] = []
|
|
116
|
+
|
|
117
|
+
reportModel.cveArray.forEach(cve => cveNames.push(cve.name as string))
|
|
118
|
+
|
|
119
|
+
const boldHeader = chalk.bold(`${highestSeverity} | Vulnerable Library`)
|
|
120
|
+
const cvePluralised = numOfCVEs > 1 ? 'CVEs' : 'CVE'
|
|
121
|
+
console.log(
|
|
122
|
+
`\n ${boldHeader} ${name} (${version}) has ${numOfCVEs} known ${cvePluralised}`
|
|
123
|
+
)
|
|
124
|
+
console.log(` ${cveNames.join(', ')}`)
|
|
125
|
+
console.log(chalk.bold(' How to fix: Update to latest version'))
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class ReportLibraryModel {
|
|
2
|
+
name: string
|
|
3
|
+
cveArray: ReportCVEModel[]
|
|
4
|
+
|
|
5
|
+
constructor (name: string, cveArray: ReportCVEModel[]){
|
|
6
|
+
this.name = name
|
|
7
|
+
this.cveArray = cveArray
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class ReportCVEModel {
|
|
12
|
+
name?: string
|
|
13
|
+
description?: string
|
|
14
|
+
authentication?: string
|
|
15
|
+
references?: []
|
|
16
|
+
severityCode?: string
|
|
17
|
+
cvss3SeverityCode?: string
|
|
18
|
+
|
|
19
|
+
constructor (
|
|
20
|
+
name: string,
|
|
21
|
+
description: string,
|
|
22
|
+
severityCode: string,
|
|
23
|
+
cvss3SeverityCode: string
|
|
24
|
+
){
|
|
25
|
+
this.name = name
|
|
26
|
+
this.description = description
|
|
27
|
+
this.severityCode = severityCode
|
|
28
|
+
this.cvss3SeverityCode = cvss3SeverityCode
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {ReportSeverityModel} from "./reportSeverityModel";
|
|
2
|
+
import {ReportCVEModel} from "./reportLibraryModel";
|
|
3
|
+
|
|
4
|
+
export class ReportList {
|
|
5
|
+
reportOutputList: ReportModelStructure[]
|
|
6
|
+
|
|
7
|
+
constructor (){
|
|
8
|
+
this.reportOutputList = []
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class ReportModelStructure {
|
|
13
|
+
compositeKey: ReportCompositeKey;
|
|
14
|
+
cveArray: ReportCVEModel[];
|
|
15
|
+
|
|
16
|
+
constructor (compositeKey: ReportCompositeKey, cveArray: ReportCVEModel[]){
|
|
17
|
+
this.compositeKey = compositeKey
|
|
18
|
+
this.cveArray = cveArray
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class ReportCompositeKey {
|
|
23
|
+
libraryName!: string;
|
|
24
|
+
libraryVersion!: string;
|
|
25
|
+
highestSeverity!: ReportSeverityModel;
|
|
26
|
+
|
|
27
|
+
constructor (libraryName: string, libraryVersion: string, highestSeverity: ReportSeverityModel){
|
|
28
|
+
this.libraryName = libraryName
|
|
29
|
+
this.libraryVersion = libraryVersion
|
|
30
|
+
this.highestSeverity = highestSeverity
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createLibraryHeader,
|
|
3
|
+
getReport,
|
|
4
|
+
printVulnerabilityResponse
|
|
5
|
+
} from './commonReportingFunctions'
|
|
6
|
+
import {
|
|
7
|
+
convertGenericToTypedLibraries,
|
|
8
|
+
severityCount
|
|
9
|
+
} from './utils/reportUtils'
|
|
10
|
+
|
|
11
|
+
export async function vulnerabilityReport(
|
|
12
|
+
analysis: any,
|
|
13
|
+
applicationId: string,
|
|
14
|
+
reportId: string
|
|
15
|
+
) {
|
|
16
|
+
const reportResponse = await getReport(analysis.config, reportId)
|
|
17
|
+
|
|
18
|
+
if (reportResponse !== undefined) {
|
|
19
|
+
const id = applicationId
|
|
20
|
+
const name = analysis.config.applicationName
|
|
21
|
+
formatVulnerabilityOutput(
|
|
22
|
+
reportResponse.vulnerabilities,
|
|
23
|
+
id,
|
|
24
|
+
name,
|
|
25
|
+
analysis.config
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function formatVulnerabilityOutput(
|
|
31
|
+
libraryVulnerabilityResponse: any,
|
|
32
|
+
id: string,
|
|
33
|
+
name: string,
|
|
34
|
+
config: any
|
|
35
|
+
) {
|
|
36
|
+
const vulnerableLibraries = convertGenericToTypedLibraries(
|
|
37
|
+
libraryVulnerabilityResponse
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
const numberOfVulnerableLibraries = vulnerableLibraries.length
|
|
41
|
+
let numberOfCves = 0
|
|
42
|
+
vulnerableLibraries.forEach(lib => (numberOfCves += lib.cveArray.length))
|
|
43
|
+
|
|
44
|
+
createLibraryHeader(id, numberOfVulnerableLibraries, numberOfCves, name)
|
|
45
|
+
|
|
46
|
+
const hasSomeVulnerabilitiesReported = printVulnerabilityResponse(
|
|
47
|
+
vulnerableLibraries,
|
|
48
|
+
config
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
return [
|
|
52
|
+
hasSomeVulnerabilitiesReported,
|
|
53
|
+
numberOfCves,
|
|
54
|
+
severityCount(vulnerableLibraries)
|
|
55
|
+
]
|
|
56
|
+
}
|