@contrast/contrast 1.0.13 → 1.0.15
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/dist/audit/report/commonReportingFunctions.js +175 -116
- package/dist/audit/report/models/reportSeverityModel.js +3 -3
- package/dist/audit/report/reportingFeature.js +1 -10
- package/dist/audit/report/utils/reportUtils.js +4 -4
- package/dist/audit/save.js +7 -2
- package/dist/commands/audit/help.js +3 -1
- package/dist/commands/scan/processScan.js +0 -6
- package/dist/commands/scan/sca/scaAnalysis.js +32 -15
- package/dist/common/HTTPClient.js +22 -3
- package/dist/common/errorHandling.js +1 -2
- package/dist/constants/constants.js +10 -2
- package/dist/constants/locales.js +17 -7
- package/dist/constants.js +31 -2
- package/dist/index.js +4 -2
- package/dist/lambda/lambda.js +1 -1
- package/dist/sbom/generateSbom.js +18 -1
- package/dist/scaAnalysis/common/auditReport.js +78 -0
- package/dist/scaAnalysis/common/scaServicesUpload.js +21 -13
- package/dist/scan/formatScanOutput.js +4 -29
- package/dist/utils/commonApi.js +1 -0
- package/dist/utils/settingsHelper.js +24 -0
- package/package.json +4 -1
- package/src/audit/report/commonReportingFunctions.js +432 -0
- package/src/audit/report/models/reportSeverityModel.ts +6 -6
- package/src/audit/report/reportingFeature.ts +2 -16
- package/src/audit/report/utils/reportUtils.ts +2 -8
- package/src/audit/save.js +14 -6
- package/src/commands/audit/help.ts +3 -1
- package/src/commands/scan/processScan.js +0 -8
- package/src/commands/scan/sca/scaAnalysis.js +52 -32
- package/src/common/HTTPClient.js +26 -3
- package/src/common/errorHandling.ts +1 -2
- package/src/constants/constants.js +12 -2
- package/src/constants/locales.js +19 -7
- package/src/constants.js +34 -2
- package/src/index.ts +4 -6
- package/src/lambda/lambda.ts +1 -1
- package/src/lambda/lambdaUtils.ts +1 -1
- package/src/sbom/generateSbom.ts +20 -0
- package/src/scaAnalysis/common/auditReport.js +108 -0
- package/src/scaAnalysis/common/scaServicesUpload.js +24 -14
- package/src/scan/formatScanOutput.ts +5 -42
- package/src/utils/commonApi.js +1 -0
- package/src/utils/settingsHelper.js +26 -0
- package/src/audit/report/commonReportingFunctions.ts +0 -355
|
@@ -1,72 +1,64 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const reportOutputModel_1 = require("./models/reportOutputModel");
|
|
14
|
-
const constants_1 = require("../../constants/constants");
|
|
15
|
-
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
16
|
-
const reportGuidanceModel_1 = require("./models/reportGuidanceModel");
|
|
2
|
+
const commonApi = require('../../utils/commonApi');
|
|
3
|
+
const { ReportCompositeKey, ReportList, ReportModelStructure } = require('./models/reportListModel');
|
|
4
|
+
const { orderBy } = require('lodash');
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const { countVulnerableLibrariesBySeverity, orderByHighestPriority, findHighestSeverityCVE, findNameAndVersion, severityCountAllCVEs, findCVESeverity } = require('./utils/reportUtils');
|
|
7
|
+
const { SeverityCountModel } = require('./models/severityCountModel');
|
|
8
|
+
const { ReportOutputBodyModel, ReportOutputHeaderModel, ReportOutputModel } = require('./models/reportOutputModel');
|
|
9
|
+
const { CE_URL, CRITICAL_COLOUR, HIGH_COLOUR, LOW_COLOUR, MEDIUM_COLOUR, NOTE_COLOUR } = require('../../constants/constants');
|
|
10
|
+
const Table = require('cli-table3');
|
|
11
|
+
const { ReportGuidanceModel } = require('./models/reportGuidanceModel');
|
|
12
|
+
const i18n = require('i18n');
|
|
17
13
|
const createSummaryMessageTop = (numberOfVulnerableLibraries, numberOfCves) => {
|
|
18
14
|
numberOfVulnerableLibraries === 1
|
|
19
15
|
? console.log(`Found 1 vulnerable library containing ${numberOfCves} CVE`)
|
|
20
16
|
: console.log(`Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVEs`);
|
|
21
17
|
};
|
|
22
|
-
|
|
23
|
-
const createSummaryMessageBottom = (numberOfVulnerableLibraries) => {
|
|
18
|
+
const createSummaryMessageBottom = numberOfVulnerableLibraries => {
|
|
24
19
|
numberOfVulnerableLibraries === 1
|
|
25
|
-
? console.log(`Found 1
|
|
26
|
-
: console.log(`Found ${numberOfVulnerableLibraries}
|
|
20
|
+
? console.log(`Found 1 vulnerability`)
|
|
21
|
+
: console.log(`Found ${numberOfVulnerableLibraries} vulnerabilities`);
|
|
27
22
|
};
|
|
28
|
-
exports.createSummaryMessageBottom = createSummaryMessageBottom;
|
|
29
23
|
const getReport = async (config, reportId) => {
|
|
30
|
-
const client =
|
|
24
|
+
const client = commonApi.getHttpClient(config);
|
|
31
25
|
return client
|
|
32
26
|
.getReportById(config, reportId)
|
|
33
|
-
.then(
|
|
27
|
+
.then(res => {
|
|
34
28
|
if (res.statusCode === 200) {
|
|
35
29
|
return res.body;
|
|
36
30
|
}
|
|
37
31
|
else {
|
|
38
|
-
console.log(JSON.stringify(res));
|
|
39
|
-
|
|
32
|
+
console.log(JSON.stringify(res.statusCode));
|
|
33
|
+
commonApi.handleResponseErrors(res, 'report');
|
|
40
34
|
}
|
|
41
35
|
})
|
|
42
|
-
.catch(
|
|
36
|
+
.catch(err => {
|
|
43
37
|
console.log(err);
|
|
44
38
|
});
|
|
45
39
|
};
|
|
46
|
-
exports.getReport = getReport;
|
|
47
40
|
const printVulnerabilityResponse = (config, vulnerableLibraries, numberOfVulnerableLibraries, numberOfCves, guidance) => {
|
|
48
41
|
let hasSomeVulnerabilitiesReported = false;
|
|
49
|
-
|
|
42
|
+
printFormattedOutput(config, vulnerableLibraries, numberOfVulnerableLibraries, numberOfCves, guidance);
|
|
50
43
|
if (Object.keys(vulnerableLibraries).length > 0) {
|
|
51
44
|
hasSomeVulnerabilitiesReported = true;
|
|
52
45
|
}
|
|
53
46
|
return hasSomeVulnerabilitiesReported;
|
|
54
47
|
};
|
|
55
|
-
exports.printVulnerabilityResponse = printVulnerabilityResponse;
|
|
56
48
|
const printFormattedOutput = (config, libraries, numberOfVulnerableLibraries, numberOfCves, guidance) => {
|
|
57
|
-
|
|
49
|
+
createSummaryMessageTop(numberOfVulnerableLibraries, numberOfCves);
|
|
58
50
|
console.log();
|
|
59
|
-
const report = new
|
|
51
|
+
const report = new ReportList();
|
|
60
52
|
for (const library of libraries) {
|
|
61
|
-
const { name, version } =
|
|
62
|
-
const newOutputModel = new
|
|
53
|
+
const { name, version } = findNameAndVersion(library, config);
|
|
54
|
+
const newOutputModel = new ReportModelStructure(new ReportCompositeKey(name, version, findHighestSeverityCVE(library.cveArray), severityCountAllCVEs(library.cveArray, new SeverityCountModel()).getTotal), library.cveArray);
|
|
63
55
|
report.reportOutputList.push(newOutputModel);
|
|
64
56
|
}
|
|
65
|
-
const outputOrderedByLowestSeverityAndLowestNumOfCvesFirst =
|
|
66
|
-
|
|
57
|
+
const outputOrderedByLowestSeverityAndLowestNumOfCvesFirst = orderBy(report.reportOutputList, [
|
|
58
|
+
reportListItem => {
|
|
67
59
|
return reportListItem.compositeKey.highestSeverity.priority;
|
|
68
60
|
},
|
|
69
|
-
|
|
61
|
+
reportListItem => {
|
|
70
62
|
return reportListItem.compositeKey.numberOfSeverities;
|
|
71
63
|
}
|
|
72
64
|
], ['asc', 'desc']);
|
|
@@ -75,83 +67,81 @@ const printFormattedOutput = (config, libraries, numberOfVulnerableLibraries, nu
|
|
|
75
67
|
contrastHeaderNumCounter++;
|
|
76
68
|
const { libraryName, libraryVersion, highestSeverity } = reportModel.compositeKey;
|
|
77
69
|
const numOfCVEs = reportModel.cveArray.length;
|
|
78
|
-
const table =
|
|
79
|
-
chars: {
|
|
80
|
-
top: '',
|
|
81
|
-
'top-mid': '',
|
|
82
|
-
'top-left': '',
|
|
83
|
-
'top-right': '',
|
|
84
|
-
bottom: '',
|
|
85
|
-
'bottom-mid': '',
|
|
86
|
-
'bottom-left': '',
|
|
87
|
-
'bottom-right': '',
|
|
88
|
-
left: '',
|
|
89
|
-
'left-mid': '',
|
|
90
|
-
mid: '',
|
|
91
|
-
'mid-mid': '',
|
|
92
|
-
right: '',
|
|
93
|
-
'right-mid': '',
|
|
94
|
-
middle: ' '
|
|
95
|
-
},
|
|
96
|
-
style: { 'padding-left': 0, 'padding-right': 0 },
|
|
97
|
-
colAligns: ['right'],
|
|
98
|
-
wordWrap: true,
|
|
99
|
-
colWidths: [12, 1, 100]
|
|
100
|
-
});
|
|
70
|
+
const table = getReportTable();
|
|
101
71
|
const header = buildHeader(highestSeverity, contrastHeaderNumCounter, libraryName, libraryVersion, numOfCVEs);
|
|
102
72
|
const advice = gatherRemediationAdvice(guidance, libraryName, libraryVersion);
|
|
103
73
|
const body = buildBody(reportModel.cveArray, advice);
|
|
104
|
-
const reportOutputModel = new
|
|
74
|
+
const reportOutputModel = new ReportOutputModel(header, body);
|
|
105
75
|
table.push(reportOutputModel.body.issueMessage, reportOutputModel.body.adviceMessage);
|
|
106
76
|
console.log(reportOutputModel.header.vulnMessage, reportOutputModel.header.introducesMessage);
|
|
107
77
|
console.log(table.toString() + '\n');
|
|
108
78
|
}
|
|
109
|
-
|
|
79
|
+
createSummaryMessageBottom(numberOfVulnerableLibraries);
|
|
110
80
|
const { criticalMessage, highMessage, mediumMessage, lowMessage, noteMessage } = buildFooter(outputOrderedByLowestSeverityAndLowestNumOfCvesFirst);
|
|
111
81
|
console.log(`${criticalMessage} | ${highMessage} | ${mediumMessage} | ${lowMessage} | ${noteMessage}`);
|
|
112
|
-
if (config.host !==
|
|
113
|
-
console.log('\n' +
|
|
82
|
+
if (config.host !== CE_URL) {
|
|
83
|
+
console.log('\n' + chalk.bold('View your full dependency tree in Contrast:'));
|
|
114
84
|
console.log(`${config.host}/Contrast/static/ng/index.html#/${config.organizationId}/applications/${config.applicationId}/libs/dependency-tree`);
|
|
115
85
|
}
|
|
116
86
|
};
|
|
117
|
-
|
|
87
|
+
function getReportTable() {
|
|
88
|
+
return new Table({
|
|
89
|
+
chars: {
|
|
90
|
+
top: '',
|
|
91
|
+
'top-mid': '',
|
|
92
|
+
'top-left': '',
|
|
93
|
+
'top-right': '',
|
|
94
|
+
bottom: '',
|
|
95
|
+
'bottom-mid': '',
|
|
96
|
+
'bottom-left': '',
|
|
97
|
+
'bottom-right': '',
|
|
98
|
+
left: '',
|
|
99
|
+
'left-mid': '',
|
|
100
|
+
mid: '',
|
|
101
|
+
'mid-mid': '',
|
|
102
|
+
right: '',
|
|
103
|
+
'right-mid': '',
|
|
104
|
+
middle: ' '
|
|
105
|
+
},
|
|
106
|
+
style: { 'padding-left': 0, 'padding-right': 0 },
|
|
107
|
+
colAligns: ['right'],
|
|
108
|
+
wordWrap: true,
|
|
109
|
+
colWidths: [12, 1, 100]
|
|
110
|
+
});
|
|
111
|
+
}
|
|
118
112
|
function buildHeader(highestSeverity, contrastHeaderNum, libraryName, version, numOfCVEs) {
|
|
119
113
|
const vulnerabilityPluralised = numOfCVEs > 1 ? 'vulnerabilities' : 'vulnerability';
|
|
120
114
|
const formattedHeaderNum = buildFormattedHeaderNum(contrastHeaderNum);
|
|
121
|
-
const headerColour =
|
|
115
|
+
const headerColour = chalk.hex(highestSeverity.colour);
|
|
122
116
|
const headerNumAndSeverity = headerColour(`${formattedHeaderNum} - [${highestSeverity.severity}]`);
|
|
123
117
|
const libraryNameAndVersion = headerColour.bold(`${libraryName}-${version}`);
|
|
124
118
|
const vulnMessage = `${headerNumAndSeverity} ${libraryNameAndVersion}`;
|
|
125
119
|
const introducesMessage = `introduces ${numOfCVEs} ${vulnerabilityPluralised}`;
|
|
126
|
-
return new
|
|
120
|
+
return new ReportOutputHeaderModel(vulnMessage, introducesMessage);
|
|
127
121
|
}
|
|
128
|
-
exports.buildHeader = buildHeader;
|
|
129
122
|
function buildBody(cveArray, advice) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const { outputColour, severity, cveName } = reportSeverityModel;
|
|
133
|
-
const severityShorthand = chalk_1.default
|
|
134
|
-
.hex(outputColour)
|
|
135
|
-
.bold(`[${severity.charAt(0).toUpperCase()}]`);
|
|
136
|
-
const builtMessage = severityShorthand + cveName;
|
|
137
|
-
cveMessages.push(builtMessage);
|
|
138
|
-
});
|
|
139
|
-
const numAndSeverityType = getNumOfAndSeverityType(cveArray);
|
|
140
|
-
const issueMessage = [
|
|
141
|
-
chalk_1.default.bold('Issue'),
|
|
142
|
-
':',
|
|
143
|
-
`${numAndSeverityType} ${cveMessages.join(', ')}`
|
|
144
|
-
];
|
|
123
|
+
let assignPriorityToVulns = cveArray.map(result => findCVESeverity(result));
|
|
124
|
+
const issueMessage = getIssueRow(assignPriorityToVulns);
|
|
145
125
|
const minOrMax = advice.maximum ? advice.maximum : advice.minimum;
|
|
146
126
|
const displayAdvice = minOrMax
|
|
147
|
-
? `Change to version ${
|
|
127
|
+
? `Change to version ${chalk.bold(minOrMax)}`
|
|
148
128
|
: 'No recommendation is available according to our data. Upgrade to the latest stable is the best advice we can give.';
|
|
149
|
-
const adviceMessage = [
|
|
150
|
-
return new
|
|
129
|
+
const adviceMessage = [chalk.bold('Advice'), ':', displayAdvice];
|
|
130
|
+
return new ReportOutputBodyModel(issueMessage, adviceMessage);
|
|
131
|
+
}
|
|
132
|
+
function getIssueRow(cveArray) {
|
|
133
|
+
orderByHighestPriority(cveArray);
|
|
134
|
+
const cveMessagesList = getIssueCveMsgList(cveArray);
|
|
135
|
+
const cveNumbers = getSeverityCounts(cveArray);
|
|
136
|
+
const numAndSeverityTypeDesc = getNumOfAndSeverityType(cveNumbers);
|
|
137
|
+
return [
|
|
138
|
+
chalk.bold('Issue'),
|
|
139
|
+
':',
|
|
140
|
+
`${numAndSeverityTypeDesc} ${cveMessagesList.join(', ')}`
|
|
141
|
+
];
|
|
151
142
|
}
|
|
152
|
-
exports.buildBody = buildBody;
|
|
153
143
|
function gatherRemediationAdvice(guidance, libraryName, libraryVersion) {
|
|
154
|
-
const guidanceModel = new
|
|
144
|
+
const guidanceModel = new ReportGuidanceModel();
|
|
155
145
|
const data = guidance[libraryName + '@' + libraryVersion];
|
|
156
146
|
if (data) {
|
|
157
147
|
guidanceModel.minimum = data.minUpgradeVersion;
|
|
@@ -159,43 +149,29 @@ function gatherRemediationAdvice(guidance, libraryName, libraryVersion) {
|
|
|
159
149
|
}
|
|
160
150
|
return guidanceModel;
|
|
161
151
|
}
|
|
162
|
-
exports.gatherRemediationAdvice = gatherRemediationAdvice;
|
|
163
152
|
function buildFormattedHeaderNum(contrastHeaderNum) {
|
|
164
153
|
return `CONTRAST-${contrastHeaderNum.toString().padStart(3, '0')}`;
|
|
165
154
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const
|
|
169
|
-
const
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
const lowNumCheck = low > 0;
|
|
175
|
-
const lowDivider = lowNumCheck ? '|' : '';
|
|
176
|
-
const noteNumCheck = low > 0;
|
|
177
|
-
const noteDivider = noteNumCheck ? '|' : '';
|
|
178
|
-
const criticalMessage = criticalNumCheck
|
|
179
|
-
? `${critical} Critical ${highDivider}`
|
|
180
|
-
: '';
|
|
181
|
-
const highMessage = highNumCheck ? `${high} High ${mediumDivider}` : '';
|
|
182
|
-
const mediumMessage = mediumNumCheck ? `${medium} Medium ${lowDivider}` : '';
|
|
183
|
-
const lowMessage = lowNumCheck ? `${low} Low ${noteDivider}` : '';
|
|
184
|
-
const noteMessage = noteNumCheck ? `${note} Note` : '';
|
|
185
|
-
return `${criticalMessage} ${highMessage} ${mediumMessage} ${lowMessage} ${noteMessage}`
|
|
155
|
+
function getNumOfAndSeverityType(cveNumbers) {
|
|
156
|
+
const { critical, high, medium, low, note } = cveNumbers;
|
|
157
|
+
const criticalMsg = critical > 0 ? `${critical} Critical | ` : '';
|
|
158
|
+
const highMsg = high > 0 ? `${high} High | ` : '';
|
|
159
|
+
const mediumMsg = medium > 0 ? `${medium} Medium | ` : '';
|
|
160
|
+
const lowMsg = low > 0 ? `${low} Low | ` : '';
|
|
161
|
+
const noteMsg = note > 0 ? `${note} Note` : '';
|
|
162
|
+
return `${criticalMsg} ${highMsg} ${mediumMsg} ${lowMsg} ${noteMsg}`
|
|
186
163
|
.replace(/\s+/g, ' ')
|
|
187
164
|
.trim();
|
|
188
165
|
}
|
|
189
|
-
|
|
190
|
-
const
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
.hex(constants_1.CRITICAL_COLOUR)
|
|
166
|
+
const buildFooter = reportModelStructure => {
|
|
167
|
+
const { critical, high, medium, low, note } = countVulnerableLibrariesBySeverity(reportModelStructure);
|
|
168
|
+
const criticalMessage = chalk
|
|
169
|
+
.hex(CRITICAL_COLOUR)
|
|
194
170
|
.bold(`${critical} Critical`);
|
|
195
|
-
const highMessage =
|
|
196
|
-
const mediumMessage =
|
|
197
|
-
const lowMessage =
|
|
198
|
-
const noteMessage =
|
|
171
|
+
const highMessage = chalk.hex(HIGH_COLOUR).bold(`${high} High`);
|
|
172
|
+
const mediumMessage = chalk.hex(MEDIUM_COLOUR).bold(`${medium} Medium`);
|
|
173
|
+
const lowMessage = chalk.hex(LOW_COLOUR).bold(`${low} Low`);
|
|
174
|
+
const noteMessage = chalk.hex(NOTE_COLOUR).bold(`${note} Note`);
|
|
199
175
|
return {
|
|
200
176
|
criticalMessage,
|
|
201
177
|
highMessage,
|
|
@@ -204,3 +180,86 @@ const buildFooter = (reportModelStructure) => {
|
|
|
204
180
|
noteMessage
|
|
205
181
|
};
|
|
206
182
|
};
|
|
183
|
+
const getIssueCveMsgList = results => {
|
|
184
|
+
const cveMessages = [];
|
|
185
|
+
results.forEach(reportSeverityModel => {
|
|
186
|
+
const { colour, severity, name } = reportSeverityModel;
|
|
187
|
+
const severityShorthand = chalk
|
|
188
|
+
.hex(colour)
|
|
189
|
+
.bold(`[${severity.charAt(0).toUpperCase()}]`);
|
|
190
|
+
const builtMessage = severityShorthand + name;
|
|
191
|
+
cveMessages.push(builtMessage);
|
|
192
|
+
});
|
|
193
|
+
return cveMessages;
|
|
194
|
+
};
|
|
195
|
+
const getSeverityCounts = results => {
|
|
196
|
+
const acc = {
|
|
197
|
+
critical: 0,
|
|
198
|
+
high: 0,
|
|
199
|
+
medium: 0,
|
|
200
|
+
low: 0,
|
|
201
|
+
note: 0,
|
|
202
|
+
total: 0
|
|
203
|
+
};
|
|
204
|
+
if (results && results.length > 0) {
|
|
205
|
+
results.forEach(i => {
|
|
206
|
+
acc[i.severity.toLowerCase()] += 1;
|
|
207
|
+
acc.total += 1;
|
|
208
|
+
return acc;
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return acc;
|
|
212
|
+
};
|
|
213
|
+
const printNoVulnFoundMsg = () => {
|
|
214
|
+
console.log(i18n.__('scanNoVulnerabilitiesFound'));
|
|
215
|
+
console.log(i18n.__('scanNoVulnerabilitiesFoundSecureCode'));
|
|
216
|
+
console.log(i18n.__('scanNoVulnerabilitiesFoundGoodWork'));
|
|
217
|
+
console.log(chalk.bold(`Found 0 vulnerabilities`));
|
|
218
|
+
console.log(i18n.__('foundDetailedVulnerabilities', String(0), String(0), String(0), String(0), String(0)));
|
|
219
|
+
};
|
|
220
|
+
const printVulnInfo = projectOverview => {
|
|
221
|
+
const totalVulnerabilities = projectOverview.total;
|
|
222
|
+
createSummaryMessageBottom(totalVulnerabilities);
|
|
223
|
+
const formattedValues = severityFormatted(projectOverview);
|
|
224
|
+
console.log(i18n.__('foundDetailedVulnerabilities', String(formattedValues.criticalFormatted), String(formattedValues.highFormatted), String(formattedValues.mediumFormatted), String(formattedValues.lowFormatted), String(formattedValues.noteFormatted)));
|
|
225
|
+
};
|
|
226
|
+
const severityFormatted = projectOverview => {
|
|
227
|
+
const criticalFormatted = chalk
|
|
228
|
+
.hex(CRITICAL_COLOUR)
|
|
229
|
+
.bold(`${projectOverview.critical} Critical`);
|
|
230
|
+
const highFormatted = chalk
|
|
231
|
+
.hex(HIGH_COLOUR)
|
|
232
|
+
.bold(`${projectOverview.high} High`);
|
|
233
|
+
const mediumFormatted = chalk
|
|
234
|
+
.hex(MEDIUM_COLOUR)
|
|
235
|
+
.bold(`${projectOverview.medium} Medium`);
|
|
236
|
+
const lowFormatted = chalk.hex(LOW_COLOUR).bold(`${projectOverview.low} Low`);
|
|
237
|
+
const noteFormatted = chalk
|
|
238
|
+
.hex(NOTE_COLOUR)
|
|
239
|
+
.bold(`${projectOverview.note} Note`);
|
|
240
|
+
return {
|
|
241
|
+
criticalFormatted,
|
|
242
|
+
highFormatted,
|
|
243
|
+
mediumFormatted,
|
|
244
|
+
lowFormatted,
|
|
245
|
+
noteFormatted
|
|
246
|
+
};
|
|
247
|
+
};
|
|
248
|
+
module.exports = {
|
|
249
|
+
createSummaryMessageTop,
|
|
250
|
+
getReport,
|
|
251
|
+
createSummaryMessageBottom,
|
|
252
|
+
printVulnerabilityResponse,
|
|
253
|
+
printFormattedOutput,
|
|
254
|
+
getReportTable,
|
|
255
|
+
buildHeader,
|
|
256
|
+
buildBody,
|
|
257
|
+
getIssueRow,
|
|
258
|
+
gatherRemediationAdvice,
|
|
259
|
+
buildFormattedHeaderNum,
|
|
260
|
+
getNumOfAndSeverityType,
|
|
261
|
+
getIssueCveMsgList,
|
|
262
|
+
getSeverityCounts,
|
|
263
|
+
printNoVulnFoundMsg,
|
|
264
|
+
printVulnInfo
|
|
265
|
+
};
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ReportSeverityModel = void 0;
|
|
4
4
|
class ReportSeverityModel {
|
|
5
|
-
constructor(severity, priority,
|
|
5
|
+
constructor(severity, priority, colour, name) {
|
|
6
6
|
this.severity = severity;
|
|
7
7
|
this.priority = priority;
|
|
8
|
-
this.
|
|
9
|
-
this.
|
|
8
|
+
this.colour = colour;
|
|
9
|
+
this.name = name;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
exports.ReportSeverityModel = ReportSeverityModel;
|
|
@@ -22,15 +22,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
-
};
|
|
28
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
26
|
exports.vulnerabilityReportV2 = exports.formatVulnerabilityOutput = exports.convertJSDotNetPython = exports.convertKeysToStandardFormat = void 0;
|
|
30
27
|
const commonReportingFunctions_1 = require("./commonReportingFunctions");
|
|
31
28
|
const reportUtils_1 = require("./utils/reportUtils");
|
|
32
|
-
const i18n_1 = __importDefault(require("i18n"));
|
|
33
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
34
29
|
const constants = __importStar(require("../../constants/constants"));
|
|
35
30
|
const severityCountModel_1 = require("./models/severityCountModel");
|
|
36
31
|
const common = __importStar(require("../../common/fail"));
|
|
@@ -67,11 +62,7 @@ function formatVulnerabilityOutput(libraryVulnerabilityResponse, id, config, rem
|
|
|
67
62
|
const guidance = convertKeysToStandardFormat(config, remediationGuidance);
|
|
68
63
|
const numberOfVulnerableLibraries = vulnerableLibraries.length;
|
|
69
64
|
if (numberOfVulnerableLibraries === 0) {
|
|
70
|
-
|
|
71
|
-
console.log(i18n_1.default.__('scanNoVulnerabilitiesFoundSecureCode'));
|
|
72
|
-
console.log(i18n_1.default.__('scanNoVulnerabilitiesFoundGoodWork'));
|
|
73
|
-
console.log(chalk_1.default.bold(`Found ${numberOfVulnerableLibraries} vulnerabilities`));
|
|
74
|
-
console.log(i18n_1.default.__('foundDetailedVulnerabilities', String(0), String(0), String(0), String(0), String(0)));
|
|
65
|
+
(0, commonReportingFunctions_1.printNoVulnFoundMsg)();
|
|
75
66
|
return [false, 0, [new severityCountModel_1.SeverityCountModel()]];
|
|
76
67
|
}
|
|
77
68
|
else {
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.countVulnerableLibrariesBySeverity = exports.findNameAndVersion = exports.severityCountSingleCVE = exports.severityCountAllCVEs = exports.severityCountAllLibraries = exports.convertGenericToTypedLibraryVulns = exports.findCVESeverity = exports.
|
|
6
|
+
exports.countVulnerableLibrariesBySeverity = exports.findNameAndVersion = exports.severityCountSingleCVE = exports.severityCountAllCVEs = exports.severityCountAllLibraries = exports.convertGenericToTypedLibraryVulns = exports.findCVESeverity = exports.orderByHighestPriority = exports.findHighestSeverityCVE = void 0;
|
|
7
7
|
const reportLibraryModel_1 = require("../models/reportLibraryModel");
|
|
8
8
|
const reportSeverityModel_1 = require("../models/reportSeverityModel");
|
|
9
9
|
const constants_1 = __importDefault(require("../../../constants/constants"));
|
|
@@ -16,10 +16,10 @@ function findHighestSeverityCVE(cveArray) {
|
|
|
16
16
|
return (0, lodash_1.orderBy)(mappedToReportSeverityModels, cve => cve?.priority)[0];
|
|
17
17
|
}
|
|
18
18
|
exports.findHighestSeverityCVE = findHighestSeverityCVE;
|
|
19
|
-
function
|
|
20
|
-
return (0, lodash_1.orderBy)(cves
|
|
19
|
+
function orderByHighestPriority(cves) {
|
|
20
|
+
return (0, lodash_1.orderBy)(cves, ['priority'], ['asc']);
|
|
21
21
|
}
|
|
22
|
-
exports.
|
|
22
|
+
exports.orderByHighestPriority = orderByHighestPriority;
|
|
23
23
|
function findCVESeverity(cve) {
|
|
24
24
|
const cveName = cve.name;
|
|
25
25
|
if (cve.cvss3SeverityCode === 'CRITICAL' || cve.severityCode === 'CRITICAL') {
|
package/dist/audit/save.js
CHANGED
|
@@ -5,7 +5,7 @@ const chalk = require('chalk');
|
|
|
5
5
|
const save = require('../commands/audit/saveFile');
|
|
6
6
|
const sbom = require('../sbom/generateSbom');
|
|
7
7
|
const { SBOM_CYCLONE_DX_FILE, SBOM_SPDX_FILE } = require('../constants/constants');
|
|
8
|
-
async function auditSave(config) {
|
|
8
|
+
async function auditSave(config, reportId) {
|
|
9
9
|
let fileFormat;
|
|
10
10
|
switch (config.save) {
|
|
11
11
|
case null:
|
|
@@ -19,7 +19,12 @@ async function auditSave(config) {
|
|
|
19
19
|
break;
|
|
20
20
|
}
|
|
21
21
|
if (fileFormat) {
|
|
22
|
-
|
|
22
|
+
if (config.experimental) {
|
|
23
|
+
save.saveFile(config, fileFormat, await sbom.generateSCASbom(config, fileFormat, reportId));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
save.saveFile(config, fileFormat, await sbom.generateSbom(config, fileFormat));
|
|
27
|
+
}
|
|
23
28
|
const filename = `${config.applicationId}-sbom-${fileFormat}.json`;
|
|
24
29
|
if (fs.existsSync(filename)) {
|
|
25
30
|
console.log(i18n.__('auditSBOMSaveSuccess') + ` - ${filename}`);
|
|
@@ -4,18 +4,12 @@ const { startScan } = require('../../scan/scanController');
|
|
|
4
4
|
const { saveScanFile } = require('../../utils/saveFile');
|
|
5
5
|
const { ScanResultsModel } = require('../../scan/models/scanResultsModel');
|
|
6
6
|
const { formatScanOutput } = require('../../scan/formatScanOutput');
|
|
7
|
-
const { processSca } = require('./sca/scaAnalysis');
|
|
8
7
|
const common = require('../../common/fail');
|
|
9
8
|
const { sendTelemetryConfigAsObject } = require('../../telemetry/telemetry');
|
|
10
9
|
const chalk = require('chalk');
|
|
11
|
-
const generalAPI = require('../../utils/generalAPI');
|
|
12
10
|
const processScan = async (contrastConf, argv) => {
|
|
13
11
|
let config = await scanConfig.getScanConfig(contrastConf, 'scan', argv);
|
|
14
12
|
let output = undefined;
|
|
15
|
-
config.mode = await generalAPI.getMode(config);
|
|
16
|
-
if (config.experimental) {
|
|
17
|
-
await processSca(config, argv);
|
|
18
|
-
}
|
|
19
13
|
let scanResults = new ScanResultsModel(await startScan(config));
|
|
20
14
|
await sendTelemetryConfigAsObject(config, 'scan', argv, 'SUCCESS', scanResults.scanDetail.language);
|
|
21
15
|
if (scanResults.scanResultsInstances !== undefined) {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
const autoDetection = require('../../../scan/autoDetection');
|
|
3
3
|
const javaAnalysis = require('../../../scaAnalysis/java');
|
|
4
4
|
const treeUpload = require('../../../scaAnalysis/common/treeUpload');
|
|
5
|
-
const scaUpload = require('../../../scaAnalysis/common/scaServicesUpload');
|
|
6
5
|
const auditController = require('../../audit/auditController');
|
|
7
6
|
const { supportedLanguages: { JAVA, GO, PYTHON, RUBY, JAVASCRIPT, NODE, PHP, DOTNET } } = require('../../../constants/constants');
|
|
8
7
|
const goAnalysis = require('../../../scaAnalysis/go/goAnalysis');
|
|
@@ -19,9 +18,11 @@ const { dotNetAnalysis } = require('../../../scaAnalysis/dotnet');
|
|
|
19
18
|
const { auditUsageGuide } = require('../../audit/help');
|
|
20
19
|
const rootFile = require('../../../audit/languageAnalysisEngine/getProjectRootFilenames');
|
|
21
20
|
const path = require('path');
|
|
22
|
-
const
|
|
21
|
+
const auditReport = require('../../../scaAnalysis/common/auditReport');
|
|
22
|
+
const scaUpload = require('../../../scaAnalysis/common/scaServicesUpload');
|
|
23
|
+
const settingsHelper = require('../../../utils/settingsHelper');
|
|
23
24
|
const processSca = async (config) => {
|
|
24
|
-
config
|
|
25
|
+
config = await settingsHelper.getSettings(config);
|
|
25
26
|
const startTime = performance.now();
|
|
26
27
|
let filesFound;
|
|
27
28
|
if (config.help) {
|
|
@@ -76,19 +77,35 @@ const processSca = async (config) => {
|
|
|
76
77
|
if (!config.applicationId) {
|
|
77
78
|
config.applicationId = await auditController.dealWithNoAppId(config);
|
|
78
79
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
if (config.experimental) {
|
|
81
|
+
console.log('');
|
|
82
|
+
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
|
|
83
|
+
startSpinner(reportSpinner);
|
|
84
|
+
const [reports, reportId] = await scaUpload.scaTreeUpload(messageToSend, config);
|
|
85
|
+
auditReport.processAuditReport(config, reports[0]);
|
|
86
|
+
succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
|
|
87
|
+
if (config.save !== undefined) {
|
|
88
|
+
await auditSave.auditSave(config, reportId);
|
|
89
|
+
}
|
|
90
|
+
const endTime = performance.now() - startTime;
|
|
91
|
+
const scanDurationMs = endTime - startTime;
|
|
92
|
+
console.log(`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
console.log('');
|
|
96
|
+
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
|
|
97
|
+
startSpinner(reportSpinner);
|
|
98
|
+
const snapshotResponse = await treeUpload.commonSendSnapShot(messageToSend, config);
|
|
99
|
+
await pollForSnapshotCompletition(config, snapshotResponse.id, reportSpinner);
|
|
100
|
+
succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
|
|
101
|
+
await vulnerabilityReportV2(config, snapshotResponse.id);
|
|
102
|
+
if (config.save !== undefined) {
|
|
103
|
+
await auditSave.auditSave(config);
|
|
104
|
+
}
|
|
105
|
+
const endTime = performance.now() - startTime;
|
|
106
|
+
const scanDurationMs = endTime - startTime;
|
|
107
|
+
console.log(`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
|
|
88
108
|
}
|
|
89
|
-
const endTime = performance.now() - startTime;
|
|
90
|
-
const scanDurationMs = endTime - startTime;
|
|
91
|
-
console.log(`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
|
|
92
109
|
}
|
|
93
110
|
else {
|
|
94
111
|
if (filesFound.length === 0) {
|
|
@@ -185,6 +185,12 @@ HTTPClient.prototype.scaServiceReportStatus = function scaServiceReport(config,
|
|
|
185
185
|
options.url = url;
|
|
186
186
|
return requestUtils.sendRequest({ method: 'get', options });
|
|
187
187
|
};
|
|
188
|
+
HTTPClient.prototype.scaServiceIngests = function scaServiceIngests(config) {
|
|
189
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
190
|
+
let url = createScaServiceIngestsURL(config);
|
|
191
|
+
options.url = url;
|
|
192
|
+
return requestUtils.sendRequest({ method: 'get', options });
|
|
193
|
+
};
|
|
188
194
|
HTTPClient.prototype.getReportById = function getReportById(config, reportId) {
|
|
189
195
|
const options = _.cloneDeep(this.requestOptions);
|
|
190
196
|
if (config.ignoreDev) {
|
|
@@ -266,6 +272,11 @@ HTTPClient.prototype.getSbom = function getSbom(config, type) {
|
|
|
266
272
|
options.url = createSbomUrl(config, type);
|
|
267
273
|
return requestUtils.sendRequest({ method: 'get', options });
|
|
268
274
|
};
|
|
275
|
+
HTTPClient.prototype.getSCASbom = function getSbom(config, type, reportId) {
|
|
276
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
277
|
+
options.url = createSCASbomUrl(config, type, reportId);
|
|
278
|
+
return requestUtils.sendRequest({ method: 'get', options });
|
|
279
|
+
};
|
|
269
280
|
HTTPClient.prototype.getLatestVersion = function getLatestVersion() {
|
|
270
281
|
const options = _.cloneDeep(this.requestOptions);
|
|
271
282
|
options.url =
|
|
@@ -321,13 +332,18 @@ function createSnapshotURL(config) {
|
|
|
321
332
|
return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/${config.applicationId}/snapshots`;
|
|
322
333
|
}
|
|
323
334
|
function createScaServiceReportURL(config, reportId) {
|
|
324
|
-
return
|
|
335
|
+
return `${config.host}/Contrast/api/sca/organizations/${config.organizationId}/libraries/applications/${config.applicationId}/reports/${reportId}`;
|
|
325
336
|
}
|
|
326
337
|
function createScaServiceReportStatusURL(config, reportId) {
|
|
327
|
-
return
|
|
338
|
+
return `${config.host}/Contrast/api/sca/organizations/${config.organizationId}/libraries/ingests/${reportId}/status`;
|
|
339
|
+
}
|
|
340
|
+
function createScaServiceIngestsURL(config) {
|
|
341
|
+
return `${config.host}/Contrast/api/sca/organizations/${config.organizationId}/libraries/ingests`;
|
|
328
342
|
}
|
|
329
343
|
function createScaServiceIngestURL(config) {
|
|
330
|
-
|
|
344
|
+
let baseUrl = `${config.host}/Contrast/api/sca/organizations/${config.organizationId}/libraries/ingests/tree`;
|
|
345
|
+
baseUrl = config.track ? baseUrl.concat('?persist=true') : baseUrl;
|
|
346
|
+
return baseUrl;
|
|
331
347
|
}
|
|
332
348
|
const createAppCreateURL = config => {
|
|
333
349
|
return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/create`;
|
|
@@ -353,6 +369,9 @@ function createDataUrl() {
|
|
|
353
369
|
function createSbomUrl(config, type) {
|
|
354
370
|
return `${config.host}/Contrast/api/ng/${config.organizationId}/applications/${config.applicationId}/libraries/sbom/${type}`;
|
|
355
371
|
}
|
|
372
|
+
function createSCASbomUrl(config, type, reportId) {
|
|
373
|
+
return `${config.host}/Contrast/api/sca/organizations/${config.organizationId}/libraries/applications/${config.applicationId}/sbom/${reportId}?toolType=${type}`;
|
|
374
|
+
}
|
|
356
375
|
function createTelemetryEventUrl(config) {
|
|
357
376
|
return `${config.host}/Contrast/api/sast/organizations/${config.organizationId}/cli`;
|
|
358
377
|
}
|
|
@@ -47,8 +47,7 @@ const reportFailureError = () => {
|
|
|
47
47
|
console.log(i18n_1.default.__('auditReportFailureMessage'));
|
|
48
48
|
};
|
|
49
49
|
exports.reportFailureError = reportFailureError;
|
|
50
|
-
const genericError = (
|
|
51
|
-
console.log(missingCliOption);
|
|
50
|
+
const genericError = () => {
|
|
52
51
|
console.error(i18n_1.default.__('genericErrorMessage'));
|
|
53
52
|
process.exit(1);
|
|
54
53
|
};
|