@contrast/contrast 1.0.18 → 1.0.20
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 +3 -4
- package/dist/audit/report/models/reportListModel.js +2 -1
- package/dist/audit/report/reportingFeature.js +1 -1
- package/dist/audit/report/utils/reportUtils.js +30 -11
- package/dist/cliConstants.js +1 -0
- package/dist/commands/audit/auditConfig.js +1 -2
- package/dist/commands/auth/auth.js +43 -7
- package/dist/commands/scan/sca/scaAnalysis.js +4 -2
- package/dist/common/HTTPClient.js +4 -4
- package/dist/common/errorHandling.js +13 -1
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +18 -2
- package/dist/scaAnalysis/common/auditReport.js +16 -60
- package/dist/scaAnalysis/common/commonReportingFunctionsSca.js +154 -0
- package/dist/scaAnalysis/common/models/ScaReportModel.js +45 -0
- package/dist/scaAnalysis/common/scaServicesUpload.js +4 -3
- package/dist/scaAnalysis/common/utils/reportUtilsSca.js +76 -0
- package/dist/scaAnalysis/java/analysis.js +1 -28
- package/dist/scaAnalysis/java/index.js +1 -13
- package/dist/scan/formatScanOutput.js +19 -13
- package/dist/utils/getConfig.js +1 -1
- package/dist/utils/paramsUtil/configStoreParams.js +1 -12
- package/dist/utils/paramsUtil/paramHandler.js +1 -7
- package/package.json +5 -1
- package/src/audit/report/commonReportingFunctions.js +7 -5
- package/src/audit/report/models/reportListModel.ts +12 -2
- package/src/audit/report/reportingFeature.ts +1 -1
- package/src/audit/report/utils/reportUtils.ts +4 -4
- package/src/cliConstants.js +1 -0
- package/src/commands/audit/auditConfig.js +1 -2
- package/src/commands/auth/auth.js +49 -7
- package/src/commands/scan/sca/scaAnalysis.js +7 -2
- package/src/common/HTTPClient.js +5 -4
- package/src/common/errorHandling.js +14 -1
- package/src/constants/constants.js +1 -1
- package/src/constants/locales.js +19 -2
- package/src/scaAnalysis/common/auditReport.js +25 -80
- package/src/scaAnalysis/common/commonReportingFunctionsSca.js +276 -0
- package/src/scaAnalysis/common/models/ScaReportModel.ts +81 -0
- package/src/scaAnalysis/common/scaServicesUpload.js +5 -3
- package/src/scaAnalysis/common/utils/reportUtilsSca.ts +123 -0
- package/src/scaAnalysis/java/analysis.js +1 -28
- package/src/scaAnalysis/java/index.js +1 -18
- package/src/scan/formatScanOutput.ts +28 -17
- package/src/utils/getConfig.ts +1 -2
- package/src/utils/paramsUtil/configStoreParams.js +1 -14
- package/src/utils/paramsUtil/paramHandler.js +1 -9
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const i18n = require('i18n')
|
|
2
|
+
const chalk = require('chalk')
|
|
2
3
|
|
|
3
4
|
const libraryAnalysisError = () => {
|
|
4
5
|
console.log(i18n.__('libraryAnalysisError'))
|
|
@@ -124,6 +125,17 @@ const findCommandOnError = unknownOptions => {
|
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
|
|
128
|
+
const commonMessageFormatter = (message, fail) => {
|
|
129
|
+
console.log(chalk.bold(i18n.__(message.title)))
|
|
130
|
+
console.log(i18n.__(message.body))
|
|
131
|
+
if (message.extra) {
|
|
132
|
+
console.log(i18n.__(message.extra))
|
|
133
|
+
}
|
|
134
|
+
if (fail) {
|
|
135
|
+
process.exit(1)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
127
139
|
module.exports = {
|
|
128
140
|
genericError,
|
|
129
141
|
unauthenticatedError,
|
|
@@ -140,5 +152,6 @@ module.exports = {
|
|
|
140
152
|
reportFailureError,
|
|
141
153
|
maxAppError,
|
|
142
154
|
parametersError,
|
|
143
|
-
invalidHostNameError
|
|
155
|
+
invalidHostNameError,
|
|
156
|
+
commonMessageFormatter
|
|
144
157
|
}
|
package/src/constants/locales.js
CHANGED
|
@@ -194,7 +194,10 @@ const en_locales = () => {
|
|
|
194
194
|
chalk.bold('\ncontrast scan') +
|
|
195
195
|
" to run Contrast's industry leading SAST scanner. \nSupports Java, JavaScript and .Net \n" +
|
|
196
196
|
chalk.bold('\ncontrast audit') +
|
|
197
|
-
' to find vulnerabilities in your open source dependencies
|
|
197
|
+
' to find vulnerabilities in your open source dependencies.' +
|
|
198
|
+
'\nSupports Java, .NET, Node, Ruby, Python, Go and PHP.' +
|
|
199
|
+
'\nOur CLI runs native build tools to generate a complete dependency tree.' +
|
|
200
|
+
'\nIf you are running on untrusted code, consider running in a sandbox.\n' +
|
|
198
201
|
chalk.bold('\ncontrast lambda') +
|
|
199
202
|
' to secure your AWS serverless functions. \nSupports Java and Python \n' +
|
|
200
203
|
chalk.bold('\ncontrast help') +
|
|
@@ -259,7 +262,8 @@ const en_locales = () => {
|
|
|
259
262
|
)} Maven build platform including the dependency plugin.
|
|
260
263
|
${chalk.bold('Or')} build.gradle ${chalk.bold(
|
|
261
264
|
'and'
|
|
262
|
-
)} gradle dependencies or ./gradlew dependencies must be supported
|
|
265
|
+
)} gradle dependencies or ./gradlew dependencies must be supported
|
|
266
|
+
If you are running on untrusted code, consider running in a sandbox.`,
|
|
263
267
|
constantsAuditPrerequisitesContentDotNetMessage: `
|
|
264
268
|
${chalk.bold(
|
|
265
269
|
'.NET framework and .NET core:'
|
|
@@ -317,6 +321,19 @@ const en_locales = () => {
|
|
|
317
321
|
'Join the discussion:'
|
|
318
322
|
),
|
|
319
323
|
commonHelpJoinDiscussionText: ' https://dev.to/codesec',
|
|
324
|
+
authCommand: {
|
|
325
|
+
credentialsAccepted: {
|
|
326
|
+
title: 'Credentials accepted',
|
|
327
|
+
body: 'Now run contrast audit, lambda or scan',
|
|
328
|
+
extra: 'Or contrast help for full list of commands'
|
|
329
|
+
},
|
|
330
|
+
credentialsMissing: {
|
|
331
|
+
title: 'Credentials missing',
|
|
332
|
+
body: 'You have not entered the right parameters or enough information',
|
|
333
|
+
extra:
|
|
334
|
+
'Please check and try again e.g. contrast auth --api-key yourApiKey--organization-id yourOrg --authorization yourAuth --host https://yourHost\nOr contrast help for full list of commands'
|
|
335
|
+
}
|
|
336
|
+
},
|
|
320
337
|
...lambda
|
|
321
338
|
}
|
|
322
339
|
}
|
|
@@ -1,105 +1,50 @@
|
|
|
1
1
|
const {
|
|
2
2
|
getSeverityCounts,
|
|
3
|
-
createSummaryMessageTop,
|
|
4
|
-
printVulnInfo,
|
|
5
|
-
getReportTable,
|
|
6
|
-
getIssueRow,
|
|
7
3
|
printNoVulnFoundMsg
|
|
8
4
|
} = require('../../audit/report/commonReportingFunctions')
|
|
9
|
-
const { orderBy } = require('lodash')
|
|
10
|
-
const { assignBySeverity } = require('../../scan/formatScanOutput')
|
|
11
|
-
const chalk = require('chalk')
|
|
12
|
-
const { CE_URL } = require('../../constants/constants')
|
|
13
5
|
const common = require('../../common/fail')
|
|
14
|
-
const
|
|
6
|
+
const { printFormattedOutputSca } = require('./commonReportingFunctionsSca')
|
|
15
7
|
|
|
16
|
-
const processAuditReport = (config,
|
|
8
|
+
const processAuditReport = (config, reportModelList) => {
|
|
17
9
|
let severityCounts = {}
|
|
18
|
-
if (
|
|
19
|
-
severityCounts = formatScaServicesReport(config,
|
|
10
|
+
if (reportModelList !== undefined) {
|
|
11
|
+
severityCounts = formatScaServicesReport(config, reportModelList)
|
|
20
12
|
}
|
|
21
13
|
|
|
22
14
|
if (config.fail) {
|
|
23
15
|
common.processFail(config, severityCounts)
|
|
24
16
|
}
|
|
25
17
|
}
|
|
26
|
-
const formatScaServicesReport = (config,
|
|
27
|
-
const projectOverviewCount = getSeverityCounts(
|
|
18
|
+
const formatScaServicesReport = (config, reportModelList) => {
|
|
19
|
+
const projectOverviewCount = getSeverityCounts(reportModelList)
|
|
28
20
|
|
|
29
21
|
if (projectOverviewCount.total === 0) {
|
|
30
22
|
printNoVulnFoundMsg()
|
|
31
|
-
return projectOverviewCount
|
|
32
23
|
} else {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const table = getReportTable()
|
|
36
|
-
let contrastHeaderNumCounter = 0
|
|
37
|
-
let assignPriorityToResults = results.map(result =>
|
|
38
|
-
assignBySeverity(result, result)
|
|
39
|
-
)
|
|
40
|
-
const numberOfVulns = results
|
|
41
|
-
.map(result => result.vulnerabilities)
|
|
42
|
-
.reduce((a, b) => {
|
|
43
|
-
return (total += b.length)
|
|
44
|
-
}, 0)
|
|
45
|
-
const outputOrderedByLowestSeverityAndLowestNumOfCvesFirst = orderBy(
|
|
46
|
-
assignPriorityToResults,
|
|
47
|
-
[
|
|
48
|
-
reportListItem => {
|
|
49
|
-
return reportListItem.priority
|
|
50
|
-
},
|
|
51
|
-
reportListItem => {
|
|
52
|
-
return reportListItem.vulnerabilities.length
|
|
53
|
-
}
|
|
54
|
-
],
|
|
55
|
-
['asc', 'desc']
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
for (const result of outputOrderedByLowestSeverityAndLowestNumOfCvesFirst) {
|
|
59
|
-
contrastHeaderNumCounter++
|
|
60
|
-
const cvesNum = result.vulnerabilities.length
|
|
61
|
-
const grammaticallyCorrectVul =
|
|
62
|
-
result.vulnerabilities.length > 1 ? 'vulnerabilities' : 'vulnerability'
|
|
63
|
-
|
|
64
|
-
const headerColour = chalk.hex(result.colour)
|
|
65
|
-
const headerRow = [
|
|
66
|
-
headerColour(
|
|
67
|
-
`CONTRAST-${contrastHeaderNumCounter.toString().padStart(3, '0')}`
|
|
68
|
-
),
|
|
69
|
-
headerColour(`-`),
|
|
70
|
-
headerColour(`[${result.severity}] `) +
|
|
71
|
-
headerColour.bold(`${result.artifactName}`) +
|
|
72
|
-
` introduces ${cvesNum} ${grammaticallyCorrectVul}`
|
|
73
|
-
]
|
|
24
|
+
const numberOfVulnerableLibraries = reportModelList.map(library => {
|
|
25
|
+
let count = 0
|
|
74
26
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
`Change to version ${result.remediationAdvice.latestStableVersion}`
|
|
79
|
-
]
|
|
27
|
+
if (library.vulnerabilities.length > 0) {
|
|
28
|
+
count++
|
|
29
|
+
}
|
|
80
30
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
)
|
|
84
|
-
const issueRow = getIssueRow(assignPriorityToVulns)
|
|
31
|
+
return count
|
|
32
|
+
}).length
|
|
85
33
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
console.log()
|
|
91
|
-
createSummaryMessageTop(numberOfCves, numberOfVulns)
|
|
92
|
-
console.log(table.toString() + '\n')
|
|
93
|
-
printVulnInfo(projectOverviewCount)
|
|
34
|
+
let numberOfCves = reportModelList.reduce(
|
|
35
|
+
(count, current) => count + current.vulnerabilities.length,
|
|
36
|
+
0
|
|
37
|
+
)
|
|
94
38
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return projectOverviewCount
|
|
39
|
+
printFormattedOutputSca(
|
|
40
|
+
config,
|
|
41
|
+
reportModelList,
|
|
42
|
+
numberOfVulnerableLibraries,
|
|
43
|
+
numberOfCves
|
|
44
|
+
)
|
|
102
45
|
}
|
|
46
|
+
|
|
47
|
+
return projectOverviewCount
|
|
103
48
|
}
|
|
104
49
|
module.exports = {
|
|
105
50
|
formatScaServicesReport,
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
const {
|
|
2
|
+
ReportList,
|
|
3
|
+
ReportModelStructure,
|
|
4
|
+
ReportCompositeKey
|
|
5
|
+
} = require('../../audit/report/models/reportListModel')
|
|
6
|
+
const {
|
|
7
|
+
countVulnerableLibrariesBySeverity
|
|
8
|
+
} = require('../../audit/report/utils/reportUtils')
|
|
9
|
+
const {
|
|
10
|
+
SeverityCountModel
|
|
11
|
+
} = require('../../audit/report/models/severityCountModel')
|
|
12
|
+
const { orderBy } = require('lodash')
|
|
13
|
+
const {
|
|
14
|
+
ReportOutputModel,
|
|
15
|
+
ReportOutputHeaderModel,
|
|
16
|
+
ReportOutputBodyModel
|
|
17
|
+
} = require('../../audit/report/models/reportOutputModel')
|
|
18
|
+
const {
|
|
19
|
+
CE_URL,
|
|
20
|
+
CRITICAL_COLOUR,
|
|
21
|
+
HIGH_COLOUR,
|
|
22
|
+
MEDIUM_COLOUR,
|
|
23
|
+
LOW_COLOUR,
|
|
24
|
+
NOTE_COLOUR
|
|
25
|
+
} = require('../../constants/constants')
|
|
26
|
+
const chalk = require('chalk')
|
|
27
|
+
const Table = require('cli-table3')
|
|
28
|
+
const {
|
|
29
|
+
findHighestSeverityCVESca,
|
|
30
|
+
severityCountAllCVEsSca,
|
|
31
|
+
findCVESeveritySca,
|
|
32
|
+
orderByHighestPrioritySca
|
|
33
|
+
} = require('./utils/reportUtilsSca')
|
|
34
|
+
const {
|
|
35
|
+
buildFormattedHeaderNum
|
|
36
|
+
} = require('../../audit/report/commonReportingFunctions')
|
|
37
|
+
|
|
38
|
+
const createSummaryMessageTop = (numberOfVulnerableLibraries, numberOfCves) => {
|
|
39
|
+
numberOfVulnerableLibraries === 1
|
|
40
|
+
? console.log(
|
|
41
|
+
`\n\nFound 1 vulnerable library containing ${numberOfCves} CVE`
|
|
42
|
+
)
|
|
43
|
+
: console.log(
|
|
44
|
+
`\n\nFound ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVEs`
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const createSummaryMessageBottom = numberOfVulnerableLibraries => {
|
|
49
|
+
numberOfVulnerableLibraries === 1
|
|
50
|
+
? console.log(`Found 1 vulnerability`)
|
|
51
|
+
: console.log(`Found ${numberOfVulnerableLibraries} vulnerabilities`)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const printFormattedOutputSca = (
|
|
55
|
+
config,
|
|
56
|
+
reportModelList,
|
|
57
|
+
numberOfVulnerableLibraries,
|
|
58
|
+
numberOfCves
|
|
59
|
+
) => {
|
|
60
|
+
createSummaryMessageTop(numberOfVulnerableLibraries, numberOfCves)
|
|
61
|
+
console.log()
|
|
62
|
+
const report = new ReportList()
|
|
63
|
+
|
|
64
|
+
for (const library of reportModelList) {
|
|
65
|
+
const { artifactName, version, vulnerabilities, remediationAdvice } =
|
|
66
|
+
library
|
|
67
|
+
|
|
68
|
+
const newOutputModel = new ReportModelStructure(
|
|
69
|
+
new ReportCompositeKey(
|
|
70
|
+
artifactName,
|
|
71
|
+
version,
|
|
72
|
+
findHighestSeverityCVESca(vulnerabilities),
|
|
73
|
+
severityCountAllCVEsSca(
|
|
74
|
+
vulnerabilities,
|
|
75
|
+
new SeverityCountModel()
|
|
76
|
+
).getTotal
|
|
77
|
+
),
|
|
78
|
+
vulnerabilities,
|
|
79
|
+
remediationAdvice
|
|
80
|
+
)
|
|
81
|
+
report.reportOutputList.push(newOutputModel)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const outputOrderedByLowestSeverityAndLowestNumOfCvesFirst = orderBy(
|
|
85
|
+
report.reportOutputList,
|
|
86
|
+
[
|
|
87
|
+
reportListItem => {
|
|
88
|
+
return reportListItem.compositeKey.highestSeverity.priority
|
|
89
|
+
},
|
|
90
|
+
reportListItem => {
|
|
91
|
+
return reportListItem.compositeKey.numberOfSeverities
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
['asc', 'desc']
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
let contrastHeaderNumCounter = 0
|
|
98
|
+
for (const reportModel of outputOrderedByLowestSeverityAndLowestNumOfCvesFirst) {
|
|
99
|
+
contrastHeaderNumCounter++
|
|
100
|
+
const { libraryName, libraryVersion, highestSeverity } =
|
|
101
|
+
reportModel.compositeKey
|
|
102
|
+
|
|
103
|
+
const { cveArray, remediationAdvice } = reportModel
|
|
104
|
+
|
|
105
|
+
const numOfCVEs = reportModel.cveArray.length
|
|
106
|
+
|
|
107
|
+
const table = getReportTable()
|
|
108
|
+
|
|
109
|
+
const header = buildHeader(
|
|
110
|
+
highestSeverity,
|
|
111
|
+
contrastHeaderNumCounter,
|
|
112
|
+
libraryName,
|
|
113
|
+
libraryVersion,
|
|
114
|
+
numOfCVEs
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
const body = buildBody(cveArray, remediationAdvice)
|
|
118
|
+
|
|
119
|
+
const reportOutputModel = new ReportOutputModel(header, body)
|
|
120
|
+
|
|
121
|
+
table.push(
|
|
122
|
+
reportOutputModel.body.issueMessage,
|
|
123
|
+
reportOutputModel.body.adviceMessage
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
console.log(
|
|
127
|
+
reportOutputModel.header.vulnMessage,
|
|
128
|
+
reportOutputModel.header.introducesMessage
|
|
129
|
+
)
|
|
130
|
+
console.log(table.toString() + '\n')
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
createSummaryMessageBottom(numberOfVulnerableLibraries)
|
|
134
|
+
const {
|
|
135
|
+
criticalMessage,
|
|
136
|
+
highMessage,
|
|
137
|
+
mediumMessage,
|
|
138
|
+
lowMessage,
|
|
139
|
+
noteMessage
|
|
140
|
+
} = buildFooter(outputOrderedByLowestSeverityAndLowestNumOfCvesFirst)
|
|
141
|
+
console.log(
|
|
142
|
+
`${criticalMessage} | ${highMessage} | ${mediumMessage} | ${lowMessage} | ${noteMessage}`
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
if (config.host !== CE_URL) {
|
|
146
|
+
console.log(
|
|
147
|
+
'\n' + chalk.bold('View your full dependency tree in Contrast:')
|
|
148
|
+
)
|
|
149
|
+
console.log(
|
|
150
|
+
`${config.host}/Contrast/static/ng/index.html#/${config.organizationId}/applications/${config.applicationId}/libs/dependency-tree`
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function getReportTable() {
|
|
156
|
+
return new Table({
|
|
157
|
+
chars: {
|
|
158
|
+
top: '',
|
|
159
|
+
'top-mid': '',
|
|
160
|
+
'top-left': '',
|
|
161
|
+
'top-right': '',
|
|
162
|
+
bottom: '',
|
|
163
|
+
'bottom-mid': '',
|
|
164
|
+
'bottom-left': '',
|
|
165
|
+
'bottom-right': '',
|
|
166
|
+
left: '',
|
|
167
|
+
'left-mid': '',
|
|
168
|
+
mid: '',
|
|
169
|
+
'mid-mid': '',
|
|
170
|
+
right: '',
|
|
171
|
+
'right-mid': '',
|
|
172
|
+
middle: ' '
|
|
173
|
+
},
|
|
174
|
+
style: { 'padding-left': 0, 'padding-right': 0 },
|
|
175
|
+
colAligns: ['right'],
|
|
176
|
+
wordWrap: true,
|
|
177
|
+
colWidths: [12, 1, 100]
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function buildHeader(
|
|
182
|
+
highestSeverity,
|
|
183
|
+
contrastHeaderNum,
|
|
184
|
+
libraryName,
|
|
185
|
+
version,
|
|
186
|
+
numOfCVEs
|
|
187
|
+
) {
|
|
188
|
+
const vulnerabilityPluralised =
|
|
189
|
+
numOfCVEs > 1 ? 'vulnerabilities' : 'vulnerability'
|
|
190
|
+
const formattedHeaderNum = buildFormattedHeaderNum(contrastHeaderNum)
|
|
191
|
+
|
|
192
|
+
const headerColour = chalk.hex(highestSeverity.colour)
|
|
193
|
+
const headerNumAndSeverity = headerColour(
|
|
194
|
+
`${formattedHeaderNum} - [${highestSeverity.severity}]`
|
|
195
|
+
)
|
|
196
|
+
const libraryNameAndVersion = headerColour.bold(`${libraryName}-${version}`)
|
|
197
|
+
const vulnMessage = `${headerNumAndSeverity} ${libraryNameAndVersion}`
|
|
198
|
+
|
|
199
|
+
const introducesMessage = `introduces ${numOfCVEs} ${vulnerabilityPluralised}`
|
|
200
|
+
|
|
201
|
+
return new ReportOutputHeaderModel(vulnMessage, introducesMessage)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function buildBody(cveArray, advice) {
|
|
205
|
+
const orderedCvesWithSeverityAssigned = orderByHighestPrioritySca(
|
|
206
|
+
cveArray.map(cve => findCVESeveritySca(cve))
|
|
207
|
+
)
|
|
208
|
+
const issueMessage = getIssueRow(orderedCvesWithSeverityAssigned)
|
|
209
|
+
const adviceMessage = getAdviceRow(advice)
|
|
210
|
+
|
|
211
|
+
return new ReportOutputBodyModel(issueMessage, adviceMessage)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function getIssueRow(cveArray) {
|
|
215
|
+
const cveMessagesList = getIssueCveMsgList(cveArray)
|
|
216
|
+
return [chalk.bold('Issue'), ':', `${cveMessagesList.join(', ')}`]
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function getAdviceRow(advice) {
|
|
220
|
+
const latestOrClosest = advice.latestStableVersion
|
|
221
|
+
? advice.latestStableVersion
|
|
222
|
+
: advice.closestStableVersion
|
|
223
|
+
const displayAdvice = latestOrClosest
|
|
224
|
+
? `Change to version ${chalk.bold(latestOrClosest)}`
|
|
225
|
+
: 'No recommendation is available according to our data. Upgrade to the latest stable is the best advice we can give.'
|
|
226
|
+
|
|
227
|
+
return [chalk.bold(`Advice`), chalk.bold(`:`), `${displayAdvice}`]
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const buildFooter = reportModelStructure => {
|
|
231
|
+
const { critical, high, medium, low, note } =
|
|
232
|
+
countVulnerableLibrariesBySeverity(reportModelStructure)
|
|
233
|
+
|
|
234
|
+
const criticalMessage = chalk
|
|
235
|
+
.hex(CRITICAL_COLOUR)
|
|
236
|
+
.bold(`${critical} Critical`)
|
|
237
|
+
const highMessage = chalk.hex(HIGH_COLOUR).bold(`${high} High`)
|
|
238
|
+
const mediumMessage = chalk.hex(MEDIUM_COLOUR).bold(`${medium} Medium`)
|
|
239
|
+
const lowMessage = chalk.hex(LOW_COLOUR).bold(`${low} Low`)
|
|
240
|
+
const noteMessage = chalk.hex(NOTE_COLOUR).bold(`${note} Note`)
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
criticalMessage,
|
|
244
|
+
highMessage,
|
|
245
|
+
mediumMessage,
|
|
246
|
+
lowMessage,
|
|
247
|
+
noteMessage
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const getIssueCveMsgList = reportSeverityModels => {
|
|
252
|
+
const cveMessages = []
|
|
253
|
+
reportSeverityModels.forEach(reportSeverityModel => {
|
|
254
|
+
const { colour, severity, name } = reportSeverityModel
|
|
255
|
+
|
|
256
|
+
const severityShorthand = chalk
|
|
257
|
+
.hex(colour)
|
|
258
|
+
.bold(`[${severity.charAt(0).toUpperCase()}]`)
|
|
259
|
+
|
|
260
|
+
const builtMessage = severityShorthand + name
|
|
261
|
+
cveMessages.push(builtMessage)
|
|
262
|
+
})
|
|
263
|
+
return cveMessages
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
module.exports = {
|
|
267
|
+
createSummaryMessageTop,
|
|
268
|
+
createSummaryMessageBottom,
|
|
269
|
+
printFormattedOutputSca,
|
|
270
|
+
getReportTable,
|
|
271
|
+
buildHeader,
|
|
272
|
+
buildBody,
|
|
273
|
+
getIssueRow,
|
|
274
|
+
buildFormattedHeaderNum,
|
|
275
|
+
getIssueCveMsgList
|
|
276
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export class ScaReportModel {
|
|
2
|
+
uuid: string
|
|
3
|
+
groupName: string
|
|
4
|
+
artifactName: string
|
|
5
|
+
version: string
|
|
6
|
+
hash: string
|
|
7
|
+
fileName: string
|
|
8
|
+
libraryLanguage: string
|
|
9
|
+
vulnerable: boolean
|
|
10
|
+
privateLibrary: boolean
|
|
11
|
+
severity: string
|
|
12
|
+
releaseDate: string
|
|
13
|
+
latestVersionReleaseDate: string
|
|
14
|
+
latestVersion: string
|
|
15
|
+
versionsBehind: number
|
|
16
|
+
vulnerabilities: ScaReportVulnerabilityModel[]
|
|
17
|
+
remediationAdvice: ScaReportRemediationAdviceModel
|
|
18
|
+
|
|
19
|
+
constructor(library: any) {
|
|
20
|
+
this.uuid = library.uuid
|
|
21
|
+
this.groupName = library.groupName
|
|
22
|
+
this.artifactName = library.artifactName
|
|
23
|
+
this.version = library.version
|
|
24
|
+
this.hash = library.hash
|
|
25
|
+
this.fileName = library.fileName
|
|
26
|
+
this.libraryLanguage = library.libraryLanguage
|
|
27
|
+
this.vulnerable = library.vulnerable
|
|
28
|
+
this.privateLibrary = library.privateLibrary
|
|
29
|
+
this.severity = library.severity
|
|
30
|
+
this.releaseDate = library.releaseDate
|
|
31
|
+
this.latestVersionReleaseDate = library.latestVersionReleaseDate
|
|
32
|
+
this.latestVersion = library.latestVersion
|
|
33
|
+
this.versionsBehind = library.versionsBehind
|
|
34
|
+
this.vulnerabilities = library.vulnerabilities
|
|
35
|
+
this.remediationAdvice = library.remediationAdvice
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class ScaReportVulnerabilityModel {
|
|
40
|
+
name: string
|
|
41
|
+
description: string
|
|
42
|
+
cvss2Vector: string
|
|
43
|
+
severityValue: number
|
|
44
|
+
severity: string
|
|
45
|
+
cvss3Vector: string
|
|
46
|
+
cvss3SeverityValue: number
|
|
47
|
+
cvss3Severity: string
|
|
48
|
+
hasCvss3: boolean
|
|
49
|
+
|
|
50
|
+
constructor(
|
|
51
|
+
name: string,
|
|
52
|
+
description: string,
|
|
53
|
+
cvss2Vector: string,
|
|
54
|
+
severityValue: number,
|
|
55
|
+
severity: string,
|
|
56
|
+
cvss3Vector: string,
|
|
57
|
+
cvss3SeverityValue: number,
|
|
58
|
+
cvss3Severity: string,
|
|
59
|
+
hasCvss3: boolean
|
|
60
|
+
) {
|
|
61
|
+
this.name = name
|
|
62
|
+
this.description = description
|
|
63
|
+
this.cvss2Vector = cvss2Vector
|
|
64
|
+
this.severityValue = severityValue
|
|
65
|
+
this.severity = severity
|
|
66
|
+
this.cvss3Vector = cvss3Vector
|
|
67
|
+
this.cvss3SeverityValue = cvss3SeverityValue
|
|
68
|
+
this.cvss3Severity = cvss3Severity
|
|
69
|
+
this.hasCvss3 = hasCvss3
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export class ScaReportRemediationAdviceModel {
|
|
74
|
+
closestStableVersion: string
|
|
75
|
+
latestStableVersion: string
|
|
76
|
+
|
|
77
|
+
constructor(closestStableVersion: string, latestStableVersion: string) {
|
|
78
|
+
this.closestStableVersion = closestStableVersion
|
|
79
|
+
this.latestStableVersion = latestStableVersion
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -46,17 +46,19 @@ const scaTreeUpload = async (analysis, config) => {
|
|
|
46
46
|
if (res.body.status === 'COMPLETED') {
|
|
47
47
|
keepChecking = false
|
|
48
48
|
return client.scaServiceReport(config, reportID).then(res => {
|
|
49
|
-
|
|
49
|
+
const reportBody = res.body
|
|
50
|
+
return { reportBody, reportID }
|
|
50
51
|
})
|
|
51
52
|
}
|
|
52
53
|
})
|
|
53
54
|
|
|
54
55
|
if (!keepChecking) {
|
|
55
|
-
return
|
|
56
|
+
return { reportArray: res.reportBody, reportID }
|
|
56
57
|
}
|
|
57
58
|
await requestUtils.sleep(5000)
|
|
58
59
|
}
|
|
59
|
-
|
|
60
|
+
|
|
61
|
+
return { reportArray: res, reportID }
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
module.exports = {
|