@contrast/contrast 1.0.12 → 1.0.14
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/commands/audit/processAudit.js +10 -0
- package/dist/commands/scan/processScan.js +9 -0
- package/dist/commands/scan/sca/scaAnalysis.js +2 -0
- package/dist/common/HTTPClient.js +30 -2
- package/dist/common/errorHandling.js +1 -2
- package/dist/common/fail.js +7 -3
- package/dist/common/versionChecker.js +11 -5
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +16 -8
- package/dist/constants.js +2 -2
- package/dist/index.js +5 -3
- package/dist/lambda/lambda.js +8 -1
- package/dist/scaAnalysis/common/auditReport.js +78 -0
- package/dist/scaAnalysis/common/scaServicesUpload.js +53 -0
- package/dist/scaAnalysis/javascript/index.js +4 -0
- package/dist/scaAnalysis/javascript/scaServiceParser.js +109 -0
- package/dist/scaAnalysis/ruby/analysis.js +106 -9
- package/dist/scaAnalysis/ruby/index.js +6 -1
- package/dist/scan/formatScanOutput.js +4 -29
- package/dist/scan/scanResults.js +1 -1
- package/dist/{audit/languageAnalysisEngine/util → utils}/capabilities.js +0 -0
- package/dist/{audit/languageAnalysisEngine/util → utils}/generalAPI.js +14 -5
- 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/commands/audit/processAudit.ts +8 -0
- package/src/commands/scan/processScan.js +14 -0
- package/src/commands/scan/sca/scaAnalysis.js +9 -0
- package/src/common/HTTPClient.js +44 -2
- package/src/common/errorHandling.ts +1 -2
- package/src/common/fail.js +7 -3
- package/src/common/versionChecker.ts +16 -6
- package/src/constants/constants.js +1 -1
- package/src/constants/locales.js +17 -9
- package/src/constants.js +2 -2
- package/src/index.ts +5 -8
- package/src/lambda/lambda.ts +13 -1
- package/src/lambda/lambdaUtils.ts +1 -1
- package/src/scaAnalysis/common/auditReport.js +108 -0
- package/src/scaAnalysis/common/scaServicesUpload.js +56 -0
- package/src/scaAnalysis/javascript/index.js +4 -0
- package/src/scaAnalysis/javascript/scaServiceParser.js +145 -0
- package/src/scaAnalysis/ruby/analysis.js +137 -9
- package/src/scaAnalysis/ruby/index.js +6 -1
- package/src/scan/formatScanOutput.ts +5 -42
- package/src/scan/scanResults.js +1 -1
- package/src/{audit/languageAnalysisEngine/util → utils}/capabilities.js +0 -0
- package/src/{audit/languageAnalysisEngine/util → utils}/generalAPI.js +16 -6
- package/src/audit/report/commonReportingFunctions.ts +0 -355
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const { featuresTeamServer } = require('./capabilities');
|
|
3
3
|
const semver = require('semver');
|
|
4
|
-
const { handleResponseErrors } = require('
|
|
5
|
-
const
|
|
4
|
+
const { handleResponseErrors } = require('../common/errorHandling');
|
|
5
|
+
const commonApi = require('./commonApi');
|
|
6
|
+
const { isNil } = require('lodash');
|
|
6
7
|
const getGlobalProperties = async (config) => {
|
|
7
|
-
const client = getHttpClient(config);
|
|
8
|
+
const client = commonApi.getHttpClient(config);
|
|
8
9
|
return client
|
|
9
|
-
.getGlobalProperties(config)
|
|
10
|
+
.getGlobalProperties(config.host)
|
|
10
11
|
.then(res => {
|
|
11
12
|
if (res.statusCode === 200) {
|
|
12
13
|
return res.body;
|
|
@@ -19,6 +20,13 @@ const getGlobalProperties = async (config) => {
|
|
|
19
20
|
console.log(err);
|
|
20
21
|
});
|
|
21
22
|
};
|
|
23
|
+
const getMode = async (config) => {
|
|
24
|
+
const features = await getGlobalProperties(config);
|
|
25
|
+
if (!isNil(features?.mode)) {
|
|
26
|
+
return features.mode;
|
|
27
|
+
}
|
|
28
|
+
return '';
|
|
29
|
+
};
|
|
22
30
|
const getFeatures = version => {
|
|
23
31
|
const featuresEnabled = [];
|
|
24
32
|
featuresTeamServer.forEach(feature => {
|
|
@@ -35,5 +43,6 @@ const isFeatureEnabled = (features, featureName) => {
|
|
|
35
43
|
module.exports = {
|
|
36
44
|
getGlobalProperties,
|
|
37
45
|
getFeatures,
|
|
38
|
-
isFeatureEnabled
|
|
46
|
+
isFeatureEnabled,
|
|
47
|
+
getMode
|
|
39
48
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/contrast",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"description": "Contrast Security's command line tool",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -25,7 +25,10 @@
|
|
|
25
25
|
"test-int-scan": "jest ./test-integration/scan",
|
|
26
26
|
"test-int-audit": "jest test-integration/audit",
|
|
27
27
|
"test-int-audit-reports": "jest test-integration/audit/audit-language-reports.spec.js",
|
|
28
|
+
"test-int-scan-errors": "jest test-integration/scan/scanLocalErrors.spec.js",
|
|
29
|
+
"test-int-scan-reports": "jest test-integration/scan/scanReport.spec.js",
|
|
28
30
|
"test-int-audit-features": "jest test-integration/audit/auditFeatures/",
|
|
31
|
+
"test-int-audit-experimental": "jest test-integration/audit/audit-experimental.spec.js",
|
|
29
32
|
"format": "prettier --write \"**/*.{ts,tsx,js,json,md,yml}\" .eslintrc.*",
|
|
30
33
|
"check-format": "prettier --check \"**/*.{ts,tsx,js,json,md,yml}\" .eslintrc.*",
|
|
31
34
|
"coverage-local": "nyc --reporter=text mocha './test/**/*.spec.js'",
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
const commonApi = require('../../utils/commonApi')
|
|
2
|
+
const {
|
|
3
|
+
ReportCompositeKey,
|
|
4
|
+
ReportList,
|
|
5
|
+
ReportModelStructure
|
|
6
|
+
} = require('./models/reportListModel')
|
|
7
|
+
const { orderBy } = require('lodash')
|
|
8
|
+
const chalk = require('chalk')
|
|
9
|
+
const {
|
|
10
|
+
countVulnerableLibrariesBySeverity,
|
|
11
|
+
orderByHighestPriority,
|
|
12
|
+
findHighestSeverityCVE,
|
|
13
|
+
findNameAndVersion,
|
|
14
|
+
severityCountAllCVEs,
|
|
15
|
+
findCVESeverity
|
|
16
|
+
} = require('./utils/reportUtils')
|
|
17
|
+
const { SeverityCountModel } = require('./models/severityCountModel')
|
|
18
|
+
const {
|
|
19
|
+
ReportOutputBodyModel,
|
|
20
|
+
ReportOutputHeaderModel,
|
|
21
|
+
ReportOutputModel
|
|
22
|
+
} = require('./models/reportOutputModel')
|
|
23
|
+
const {
|
|
24
|
+
CE_URL,
|
|
25
|
+
CRITICAL_COLOUR,
|
|
26
|
+
HIGH_COLOUR,
|
|
27
|
+
LOW_COLOUR,
|
|
28
|
+
MEDIUM_COLOUR,
|
|
29
|
+
NOTE_COLOUR
|
|
30
|
+
} = require('../../constants/constants')
|
|
31
|
+
const Table = require('cli-table3')
|
|
32
|
+
const { ReportGuidanceModel } = require('./models/reportGuidanceModel')
|
|
33
|
+
const i18n = require('i18n')
|
|
34
|
+
|
|
35
|
+
const createSummaryMessageTop = (numberOfVulnerableLibraries, numberOfCves) => {
|
|
36
|
+
numberOfVulnerableLibraries === 1
|
|
37
|
+
? console.log(`Found 1 vulnerable library containing ${numberOfCves} CVE`)
|
|
38
|
+
: console.log(
|
|
39
|
+
`Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVEs`
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const createSummaryMessageBottom = numberOfVulnerableLibraries => {
|
|
44
|
+
numberOfVulnerableLibraries === 1
|
|
45
|
+
? console.log(`Found 1 vulnerability`)
|
|
46
|
+
: console.log(`Found ${numberOfVulnerableLibraries} vulnerabilities`)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const getReport = async (config, reportId) => {
|
|
50
|
+
const client = commonApi.getHttpClient(config)
|
|
51
|
+
return client
|
|
52
|
+
.getReportById(config, reportId)
|
|
53
|
+
.then(res => {
|
|
54
|
+
if (res.statusCode === 200) {
|
|
55
|
+
return res.body
|
|
56
|
+
} else {
|
|
57
|
+
console.log(JSON.stringify(res.statusCode))
|
|
58
|
+
commonApi.handleResponseErrors(res, 'report')
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
.catch(err => {
|
|
62
|
+
console.log(err)
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const printVulnerabilityResponse = (
|
|
67
|
+
config,
|
|
68
|
+
vulnerableLibraries,
|
|
69
|
+
numberOfVulnerableLibraries,
|
|
70
|
+
numberOfCves,
|
|
71
|
+
guidance
|
|
72
|
+
) => {
|
|
73
|
+
let hasSomeVulnerabilitiesReported = false
|
|
74
|
+
printFormattedOutput(
|
|
75
|
+
config,
|
|
76
|
+
vulnerableLibraries,
|
|
77
|
+
numberOfVulnerableLibraries,
|
|
78
|
+
numberOfCves,
|
|
79
|
+
guidance
|
|
80
|
+
)
|
|
81
|
+
if (Object.keys(vulnerableLibraries).length > 0) {
|
|
82
|
+
hasSomeVulnerabilitiesReported = true
|
|
83
|
+
}
|
|
84
|
+
return hasSomeVulnerabilitiesReported
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const printFormattedOutput = (
|
|
88
|
+
config,
|
|
89
|
+
libraries,
|
|
90
|
+
numberOfVulnerableLibraries,
|
|
91
|
+
numberOfCves,
|
|
92
|
+
guidance
|
|
93
|
+
) => {
|
|
94
|
+
createSummaryMessageTop(numberOfVulnerableLibraries, numberOfCves)
|
|
95
|
+
console.log()
|
|
96
|
+
const report = new ReportList()
|
|
97
|
+
|
|
98
|
+
for (const library of libraries) {
|
|
99
|
+
const { name, version } = findNameAndVersion(library, config)
|
|
100
|
+
|
|
101
|
+
const newOutputModel = new ReportModelStructure(
|
|
102
|
+
new ReportCompositeKey(
|
|
103
|
+
name,
|
|
104
|
+
version,
|
|
105
|
+
findHighestSeverityCVE(library.cveArray),
|
|
106
|
+
severityCountAllCVEs(
|
|
107
|
+
library.cveArray,
|
|
108
|
+
new SeverityCountModel()
|
|
109
|
+
).getTotal
|
|
110
|
+
),
|
|
111
|
+
library.cveArray
|
|
112
|
+
)
|
|
113
|
+
report.reportOutputList.push(newOutputModel)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const outputOrderedByLowestSeverityAndLowestNumOfCvesFirst = orderBy(
|
|
117
|
+
report.reportOutputList,
|
|
118
|
+
[
|
|
119
|
+
reportListItem => {
|
|
120
|
+
return reportListItem.compositeKey.highestSeverity.priority
|
|
121
|
+
},
|
|
122
|
+
reportListItem => {
|
|
123
|
+
return reportListItem.compositeKey.numberOfSeverities
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
['asc', 'desc']
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
let contrastHeaderNumCounter = 0
|
|
130
|
+
for (const reportModel of outputOrderedByLowestSeverityAndLowestNumOfCvesFirst) {
|
|
131
|
+
contrastHeaderNumCounter++
|
|
132
|
+
const { libraryName, libraryVersion, highestSeverity } =
|
|
133
|
+
reportModel.compositeKey
|
|
134
|
+
const numOfCVEs = reportModel.cveArray.length
|
|
135
|
+
|
|
136
|
+
const table = getReportTable()
|
|
137
|
+
|
|
138
|
+
const header = buildHeader(
|
|
139
|
+
highestSeverity,
|
|
140
|
+
contrastHeaderNumCounter,
|
|
141
|
+
libraryName,
|
|
142
|
+
libraryVersion,
|
|
143
|
+
numOfCVEs
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
const advice = gatherRemediationAdvice(
|
|
147
|
+
guidance,
|
|
148
|
+
libraryName,
|
|
149
|
+
libraryVersion
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
const body = buildBody(reportModel.cveArray, advice)
|
|
153
|
+
|
|
154
|
+
const reportOutputModel = new ReportOutputModel(header, body)
|
|
155
|
+
|
|
156
|
+
table.push(
|
|
157
|
+
reportOutputModel.body.issueMessage,
|
|
158
|
+
reportOutputModel.body.adviceMessage
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
console.log(
|
|
162
|
+
reportOutputModel.header.vulnMessage,
|
|
163
|
+
reportOutputModel.header.introducesMessage
|
|
164
|
+
)
|
|
165
|
+
console.log(table.toString() + '\n')
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
createSummaryMessageBottom(numberOfVulnerableLibraries)
|
|
169
|
+
const {
|
|
170
|
+
criticalMessage,
|
|
171
|
+
highMessage,
|
|
172
|
+
mediumMessage,
|
|
173
|
+
lowMessage,
|
|
174
|
+
noteMessage
|
|
175
|
+
} = buildFooter(outputOrderedByLowestSeverityAndLowestNumOfCvesFirst)
|
|
176
|
+
console.log(
|
|
177
|
+
`${criticalMessage} | ${highMessage} | ${mediumMessage} | ${lowMessage} | ${noteMessage}`
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
if (config.host !== CE_URL) {
|
|
181
|
+
console.log(
|
|
182
|
+
'\n' + chalk.bold('View your full dependency tree in Contrast:')
|
|
183
|
+
)
|
|
184
|
+
console.log(
|
|
185
|
+
`${config.host}/Contrast/static/ng/index.html#/${config.organizationId}/applications/${config.applicationId}/libs/dependency-tree`
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function getReportTable() {
|
|
191
|
+
return new Table({
|
|
192
|
+
chars: {
|
|
193
|
+
top: '',
|
|
194
|
+
'top-mid': '',
|
|
195
|
+
'top-left': '',
|
|
196
|
+
'top-right': '',
|
|
197
|
+
bottom: '',
|
|
198
|
+
'bottom-mid': '',
|
|
199
|
+
'bottom-left': '',
|
|
200
|
+
'bottom-right': '',
|
|
201
|
+
left: '',
|
|
202
|
+
'left-mid': '',
|
|
203
|
+
mid: '',
|
|
204
|
+
'mid-mid': '',
|
|
205
|
+
right: '',
|
|
206
|
+
'right-mid': '',
|
|
207
|
+
middle: ' '
|
|
208
|
+
},
|
|
209
|
+
style: { 'padding-left': 0, 'padding-right': 0 },
|
|
210
|
+
colAligns: ['right'],
|
|
211
|
+
wordWrap: true,
|
|
212
|
+
colWidths: [12, 1, 100]
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
function buildHeader(
|
|
216
|
+
highestSeverity,
|
|
217
|
+
contrastHeaderNum,
|
|
218
|
+
libraryName,
|
|
219
|
+
version,
|
|
220
|
+
numOfCVEs
|
|
221
|
+
) {
|
|
222
|
+
const vulnerabilityPluralised =
|
|
223
|
+
numOfCVEs > 1 ? 'vulnerabilities' : 'vulnerability'
|
|
224
|
+
const formattedHeaderNum = buildFormattedHeaderNum(contrastHeaderNum)
|
|
225
|
+
|
|
226
|
+
const headerColour = chalk.hex(highestSeverity.colour)
|
|
227
|
+
const headerNumAndSeverity = headerColour(
|
|
228
|
+
`${formattedHeaderNum} - [${highestSeverity.severity}]`
|
|
229
|
+
)
|
|
230
|
+
const libraryNameAndVersion = headerColour.bold(`${libraryName}-${version}`)
|
|
231
|
+
const vulnMessage = `${headerNumAndSeverity} ${libraryNameAndVersion}`
|
|
232
|
+
|
|
233
|
+
const introducesMessage = `introduces ${numOfCVEs} ${vulnerabilityPluralised}`
|
|
234
|
+
|
|
235
|
+
return new ReportOutputHeaderModel(vulnMessage, introducesMessage)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function buildBody(cveArray, advice) {
|
|
239
|
+
let assignPriorityToVulns = cveArray.map(result => findCVESeverity(result))
|
|
240
|
+
|
|
241
|
+
const issueMessage = getIssueRow(assignPriorityToVulns)
|
|
242
|
+
|
|
243
|
+
//todo different advice based on remediationGuidance being available or now
|
|
244
|
+
// console.log(advice)
|
|
245
|
+
|
|
246
|
+
const minOrMax = advice.maximum ? advice.maximum : advice.minimum
|
|
247
|
+
const displayAdvice = minOrMax
|
|
248
|
+
? `Change to version ${chalk.bold(minOrMax)}`
|
|
249
|
+
: 'No recommendation is available according to our data. Upgrade to the latest stable is the best advice we can give.'
|
|
250
|
+
|
|
251
|
+
const adviceMessage = [chalk.bold('Advice'), ':', displayAdvice]
|
|
252
|
+
|
|
253
|
+
return new ReportOutputBodyModel(issueMessage, adviceMessage)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function getIssueRow(cveArray) {
|
|
257
|
+
orderByHighestPriority(cveArray)
|
|
258
|
+
const cveMessagesList = getIssueCveMsgList(cveArray)
|
|
259
|
+
const cveNumbers = getSeverityCounts(cveArray)
|
|
260
|
+
const numAndSeverityTypeDesc = getNumOfAndSeverityType(cveNumbers)
|
|
261
|
+
return [
|
|
262
|
+
chalk.bold('Issue'),
|
|
263
|
+
':',
|
|
264
|
+
`${numAndSeverityTypeDesc} ${cveMessagesList.join(', ')}`
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function gatherRemediationAdvice(guidance, libraryName, libraryVersion) {
|
|
269
|
+
const guidanceModel = new ReportGuidanceModel()
|
|
270
|
+
|
|
271
|
+
const data = guidance[libraryName + '@' + libraryVersion]
|
|
272
|
+
|
|
273
|
+
if (data) {
|
|
274
|
+
guidanceModel.minimum = data.minUpgradeVersion
|
|
275
|
+
guidanceModel.maximum = data.maxUpgradeVersion
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return guidanceModel
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function buildFormattedHeaderNum(contrastHeaderNum) {
|
|
282
|
+
return `CONTRAST-${contrastHeaderNum.toString().padStart(3, '0')}`
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function getNumOfAndSeverityType(cveNumbers) {
|
|
286
|
+
const { critical, high, medium, low, note } = cveNumbers
|
|
287
|
+
|
|
288
|
+
const criticalMsg = critical > 0 ? `${critical} Critical | ` : ''
|
|
289
|
+
const highMsg = high > 0 ? `${high} High | ` : ''
|
|
290
|
+
const mediumMsg = medium > 0 ? `${medium} Medium | ` : ''
|
|
291
|
+
const lowMsg = low > 0 ? `${low} Low | ` : ''
|
|
292
|
+
const noteMsg = note > 0 ? `${note} Note` : ''
|
|
293
|
+
|
|
294
|
+
//removes/trims whitespace to single spaces
|
|
295
|
+
return `${criticalMsg} ${highMsg} ${mediumMsg} ${lowMsg} ${noteMsg}`
|
|
296
|
+
.replace(/\s+/g, ' ')
|
|
297
|
+
.trim()
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const buildFooter = reportModelStructure => {
|
|
301
|
+
const { critical, high, medium, low, note } =
|
|
302
|
+
countVulnerableLibrariesBySeverity(reportModelStructure)
|
|
303
|
+
|
|
304
|
+
const criticalMessage = chalk
|
|
305
|
+
.hex(CRITICAL_COLOUR)
|
|
306
|
+
.bold(`${critical} Critical`)
|
|
307
|
+
const highMessage = chalk.hex(HIGH_COLOUR).bold(`${high} High`)
|
|
308
|
+
const mediumMessage = chalk.hex(MEDIUM_COLOUR).bold(`${medium} Medium`)
|
|
309
|
+
const lowMessage = chalk.hex(LOW_COLOUR).bold(`${low} Low`)
|
|
310
|
+
const noteMessage = chalk.hex(NOTE_COLOUR).bold(`${note} Note`)
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
criticalMessage,
|
|
314
|
+
highMessage,
|
|
315
|
+
mediumMessage,
|
|
316
|
+
lowMessage,
|
|
317
|
+
noteMessage
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const getIssueCveMsgList = results => {
|
|
322
|
+
const cveMessages = []
|
|
323
|
+
|
|
324
|
+
results.forEach(reportSeverityModel => {
|
|
325
|
+
// @ts-ignore
|
|
326
|
+
const { colour, severity, name } = reportSeverityModel
|
|
327
|
+
|
|
328
|
+
const severityShorthand = chalk
|
|
329
|
+
.hex(colour)
|
|
330
|
+
.bold(`[${severity.charAt(0).toUpperCase()}]`)
|
|
331
|
+
|
|
332
|
+
const builtMessage = severityShorthand + name
|
|
333
|
+
cveMessages.push(builtMessage)
|
|
334
|
+
})
|
|
335
|
+
return cveMessages
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const getSeverityCounts = results => {
|
|
339
|
+
const acc = {
|
|
340
|
+
critical: 0,
|
|
341
|
+
high: 0,
|
|
342
|
+
medium: 0,
|
|
343
|
+
low: 0,
|
|
344
|
+
note: 0,
|
|
345
|
+
total: 0
|
|
346
|
+
}
|
|
347
|
+
if (results && results.length > 0) {
|
|
348
|
+
results.forEach(i => {
|
|
349
|
+
acc[i.severity.toLowerCase()] += 1
|
|
350
|
+
acc.total += 1
|
|
351
|
+
return acc
|
|
352
|
+
})
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return acc
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const printNoVulnFoundMsg = () => {
|
|
359
|
+
console.log(i18n.__('scanNoVulnerabilitiesFound'))
|
|
360
|
+
console.log(i18n.__('scanNoVulnerabilitiesFoundSecureCode'))
|
|
361
|
+
console.log(i18n.__('scanNoVulnerabilitiesFoundGoodWork'))
|
|
362
|
+
console.log(chalk.bold(`Found 0 vulnerabilities`))
|
|
363
|
+
console.log(
|
|
364
|
+
i18n.__(
|
|
365
|
+
'foundDetailedVulnerabilities',
|
|
366
|
+
String(0),
|
|
367
|
+
String(0),
|
|
368
|
+
String(0),
|
|
369
|
+
String(0),
|
|
370
|
+
String(0)
|
|
371
|
+
)
|
|
372
|
+
)
|
|
373
|
+
}
|
|
374
|
+
const printVulnInfo = projectOverview => {
|
|
375
|
+
const totalVulnerabilities = projectOverview.total
|
|
376
|
+
|
|
377
|
+
createSummaryMessageBottom(totalVulnerabilities)
|
|
378
|
+
const formattedValues = severityFormatted(projectOverview)
|
|
379
|
+
console.log(
|
|
380
|
+
i18n.__(
|
|
381
|
+
'foundDetailedVulnerabilities',
|
|
382
|
+
String(formattedValues.criticalFormatted),
|
|
383
|
+
String(formattedValues.highFormatted),
|
|
384
|
+
String(formattedValues.mediumFormatted),
|
|
385
|
+
String(formattedValues.lowFormatted),
|
|
386
|
+
String(formattedValues.noteFormatted)
|
|
387
|
+
)
|
|
388
|
+
)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const severityFormatted = projectOverview => {
|
|
392
|
+
const criticalFormatted = chalk
|
|
393
|
+
.hex(CRITICAL_COLOUR)
|
|
394
|
+
.bold(`${projectOverview.critical} Critical`)
|
|
395
|
+
const highFormatted = chalk
|
|
396
|
+
.hex(HIGH_COLOUR)
|
|
397
|
+
.bold(`${projectOverview.high} High`)
|
|
398
|
+
const mediumFormatted = chalk
|
|
399
|
+
.hex(MEDIUM_COLOUR)
|
|
400
|
+
.bold(`${projectOverview.medium} Medium`)
|
|
401
|
+
const lowFormatted = chalk.hex(LOW_COLOUR).bold(`${projectOverview.low} Low`)
|
|
402
|
+
const noteFormatted = chalk
|
|
403
|
+
.hex(NOTE_COLOUR)
|
|
404
|
+
.bold(`${projectOverview.note} Note`)
|
|
405
|
+
|
|
406
|
+
return {
|
|
407
|
+
criticalFormatted,
|
|
408
|
+
highFormatted,
|
|
409
|
+
mediumFormatted,
|
|
410
|
+
lowFormatted,
|
|
411
|
+
noteFormatted
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
module.exports = {
|
|
416
|
+
createSummaryMessageTop,
|
|
417
|
+
getReport,
|
|
418
|
+
createSummaryMessageBottom,
|
|
419
|
+
printVulnerabilityResponse,
|
|
420
|
+
printFormattedOutput,
|
|
421
|
+
getReportTable,
|
|
422
|
+
buildHeader,
|
|
423
|
+
buildBody,
|
|
424
|
+
getIssueRow,
|
|
425
|
+
gatherRemediationAdvice,
|
|
426
|
+
buildFormattedHeaderNum,
|
|
427
|
+
getNumOfAndSeverityType,
|
|
428
|
+
getIssueCveMsgList,
|
|
429
|
+
getSeverityCounts,
|
|
430
|
+
printNoVulnFoundMsg,
|
|
431
|
+
printVulnInfo
|
|
432
|
+
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
export class ReportSeverityModel {
|
|
2
2
|
severity: string
|
|
3
3
|
priority: number
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
colour: string
|
|
5
|
+
name: string
|
|
6
6
|
|
|
7
7
|
constructor(
|
|
8
8
|
severity: string,
|
|
9
9
|
priority: number,
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
colour: string,
|
|
11
|
+
name: string
|
|
12
12
|
) {
|
|
13
13
|
this.severity = severity
|
|
14
14
|
this.priority = priority
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
15
|
+
this.colour = colour
|
|
16
|
+
this.name = name
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getReport,
|
|
3
|
+
printNoVulnFoundMsg,
|
|
3
4
|
printVulnerabilityResponse
|
|
4
5
|
} from './commonReportingFunctions'
|
|
5
6
|
import {
|
|
@@ -58,22 +59,7 @@ export function formatVulnerabilityOutput(
|
|
|
58
59
|
const numberOfVulnerableLibraries = vulnerableLibraries.length
|
|
59
60
|
|
|
60
61
|
if (numberOfVulnerableLibraries === 0) {
|
|
61
|
-
|
|
62
|
-
console.log(i18n.__('scanNoVulnerabilitiesFoundSecureCode'))
|
|
63
|
-
console.log(i18n.__('scanNoVulnerabilitiesFoundGoodWork'))
|
|
64
|
-
console.log(
|
|
65
|
-
chalk.bold(`Found ${numberOfVulnerableLibraries} vulnerabilities`)
|
|
66
|
-
)
|
|
67
|
-
console.log(
|
|
68
|
-
i18n.__(
|
|
69
|
-
'foundDetailedVulnerabilities',
|
|
70
|
-
String(0),
|
|
71
|
-
String(0),
|
|
72
|
-
String(0),
|
|
73
|
-
String(0),
|
|
74
|
-
String(0)
|
|
75
|
-
)
|
|
76
|
-
)
|
|
62
|
+
printNoVulnFoundMsg()
|
|
77
63
|
return [false, 0, [new SeverityCountModel()]]
|
|
78
64
|
} else {
|
|
79
65
|
let numberOfCves = 0
|
|
@@ -30,14 +30,8 @@ export function findHighestSeverityCVE(cveArray: ReportCVEModel[]) {
|
|
|
30
30
|
return orderBy(mappedToReportSeverityModels, cve => cve?.priority)[0]
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
export function
|
|
34
|
-
cves
|
|
35
|
-
) {
|
|
36
|
-
return orderBy(
|
|
37
|
-
cves.map(cve => findCVESeverity(cve)),
|
|
38
|
-
['priority'],
|
|
39
|
-
['asc']
|
|
40
|
-
)
|
|
33
|
+
export function orderByHighestPriority(cves: ReportCVEModel[]) {
|
|
34
|
+
return orderBy(cves, ['priority'], ['asc'])
|
|
41
35
|
}
|
|
42
36
|
|
|
43
37
|
export function findCVESeverity(cve: ReportCVEModel) {
|
|
@@ -3,6 +3,7 @@ import { auditUsageGuide } from './help'
|
|
|
3
3
|
import { processSca } from '../scan/sca/scaAnalysis'
|
|
4
4
|
import { sendTelemetryConfigAsObject } from '../../telemetry/telemetry'
|
|
5
5
|
import { ContrastConf } from '../../utils/getConfig'
|
|
6
|
+
import chalk from 'chalk'
|
|
6
7
|
|
|
7
8
|
export type parameterInput = string[]
|
|
8
9
|
|
|
@@ -17,6 +18,7 @@ export const processAudit = async (
|
|
|
17
18
|
|
|
18
19
|
const config = await getAuditConfig(contrastConf, 'audit', argv)
|
|
19
20
|
await processSca(config)
|
|
21
|
+
postRunMessage()
|
|
20
22
|
await sendTelemetryConfigAsObject(
|
|
21
23
|
config,
|
|
22
24
|
'audit',
|
|
@@ -30,3 +32,9 @@ export const processAudit = async (
|
|
|
30
32
|
const printHelpMessage = () => {
|
|
31
33
|
console.log(auditUsageGuide)
|
|
32
34
|
}
|
|
35
|
+
|
|
36
|
+
const postRunMessage = () => {
|
|
37
|
+
console.log('\n' + chalk.underline.bold('Other Codesec Features:'))
|
|
38
|
+
console.log("'contrast scan' to run CodeSec’s industry leading SAST scanner")
|
|
39
|
+
console.log("'contrast lambda' to secure your AWS serverless functions\n")
|
|
40
|
+
}
|
|
@@ -6,10 +6,14 @@ const { formatScanOutput } = require('../../scan/formatScanOutput')
|
|
|
6
6
|
const { processSca } = require('./sca/scaAnalysis')
|
|
7
7
|
const common = require('../../common/fail')
|
|
8
8
|
const { sendTelemetryConfigAsObject } = require('../../telemetry/telemetry')
|
|
9
|
+
const chalk = require('chalk')
|
|
10
|
+
const generalAPI = require('../../utils/generalAPI')
|
|
9
11
|
|
|
10
12
|
const processScan = async (contrastConf, argv) => {
|
|
11
13
|
let config = await scanConfig.getScanConfig(contrastConf, 'scan', argv)
|
|
12
14
|
let output = undefined
|
|
15
|
+
config.mode = await generalAPI.getMode(config)
|
|
16
|
+
|
|
13
17
|
//try SCA analysis first
|
|
14
18
|
if (config.experimental) {
|
|
15
19
|
await processSca(config, argv)
|
|
@@ -35,6 +39,16 @@ const processScan = async (contrastConf, argv) => {
|
|
|
35
39
|
if (config.fail) {
|
|
36
40
|
common.processFail(config, output)
|
|
37
41
|
}
|
|
42
|
+
|
|
43
|
+
postRunMessage()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const postRunMessage = () => {
|
|
47
|
+
console.log('\n' + chalk.underline.bold('Other Codesec Features:'))
|
|
48
|
+
console.log(
|
|
49
|
+
"'contrast audit' to find vulnerabilities in your open source dependencies"
|
|
50
|
+
)
|
|
51
|
+
console.log("'contrast lambda' to secure your AWS serverless functions\n")
|
|
38
52
|
}
|
|
39
53
|
|
|
40
54
|
module.exports = {
|
|
@@ -27,7 +27,11 @@ const { dotNetAnalysis } = require('../../../scaAnalysis/dotnet')
|
|
|
27
27
|
const { auditUsageGuide } = require('../../audit/help')
|
|
28
28
|
const rootFile = require('../../../audit/languageAnalysisEngine/getProjectRootFilenames')
|
|
29
29
|
const path = require('path')
|
|
30
|
+
const generalAPI = require('../../../utils/generalAPI')
|
|
31
|
+
|
|
30
32
|
const processSca = async config => {
|
|
33
|
+
config.mode = await generalAPI.getMode(config)
|
|
34
|
+
|
|
31
35
|
const startTime = performance.now()
|
|
32
36
|
let filesFound
|
|
33
37
|
|
|
@@ -99,6 +103,10 @@ const processSca = async config => {
|
|
|
99
103
|
config.applicationId = await auditController.dealWithNoAppId(config)
|
|
100
104
|
}
|
|
101
105
|
|
|
106
|
+
// if (config.experimental) {
|
|
107
|
+
// // const reports = await scaUpload.scaTreeUpload(messageToSend, config)
|
|
108
|
+
// auditReport.processAuditReport(config, 'reports')
|
|
109
|
+
// } else {
|
|
102
110
|
console.log('') //empty log for space before spinner
|
|
103
111
|
//send message to TS
|
|
104
112
|
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'))
|
|
@@ -126,6 +134,7 @@ const processSca = async config => {
|
|
|
126
134
|
console.log(
|
|
127
135
|
`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`
|
|
128
136
|
)
|
|
137
|
+
// }
|
|
129
138
|
} else {
|
|
130
139
|
if (filesFound.length === 0) {
|
|
131
140
|
console.log(i18n.__('languageAnalysisNoLanguage'))
|