@contrast/contrast 1.0.8 → 1.0.9

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.
Files changed (173) hide show
  1. package/dist/audit/languageAnalysisEngine/getProjectRootFilenames.js +3 -12
  2. package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +88 -53
  3. package/dist/audit/languageAnalysisEngine/report/models/reportOutputModel.js +4 -3
  4. package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +58 -11
  5. package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +38 -5
  6. package/dist/audit/languageAnalysisEngine/sendSnapshot.js +6 -30
  7. package/dist/audit/save.js +21 -13
  8. package/dist/commands/audit/auditConfig.js +0 -16
  9. package/dist/commands/audit/auditController.js +1 -10
  10. package/dist/commands/audit/help.js +7 -24
  11. package/dist/commands/audit/processAudit.js +1 -7
  12. package/dist/commands/audit/saveFile.js +2 -2
  13. package/dist/commands/scan/sca/scaAnalysis.js +22 -9
  14. package/dist/common/HTTPClient.js +8 -8
  15. package/dist/constants/constants.js +7 -2
  16. package/dist/constants/locales.js +24 -30
  17. package/dist/constants.js +11 -9
  18. package/dist/index.js +54 -45
  19. package/dist/lambda/lambda.js +5 -2
  20. package/dist/sbom/generateSbom.js +2 -2
  21. package/dist/scaAnalysis/common/formatMessage.js +7 -1
  22. package/dist/scaAnalysis/common/treeUpload.js +4 -5
  23. package/dist/scaAnalysis/dotnet/analysis.js +43 -0
  24. package/dist/scaAnalysis/dotnet/index.js +10 -0
  25. package/dist/scaAnalysis/javascript/analysis.js +4 -7
  26. package/dist/scaAnalysis/javascript/index.js +14 -5
  27. package/dist/scaAnalysis/php/analysis.js +14 -33
  28. package/dist/scaAnalysis/php/index.js +11 -4
  29. package/dist/scaAnalysis/ruby/analysis.js +2 -10
  30. package/dist/scan/autoDetection.js +18 -21
  31. package/dist/scan/fileUtils.js +31 -12
  32. package/dist/scan/formatScanOutput.js +3 -3
  33. package/dist/scan/scanConfig.js +2 -2
  34. package/dist/utils/getConfig.js +1 -6
  35. package/package.json +2 -3
  36. package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +3 -32
  37. package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +128 -68
  38. package/src/audit/languageAnalysisEngine/report/models/reportOutputModel.ts +11 -5
  39. package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +41 -19
  40. package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +43 -4
  41. package/src/audit/languageAnalysisEngine/sendSnapshot.js +6 -32
  42. package/src/audit/save.js +32 -16
  43. package/src/commands/audit/auditConfig.ts +0 -25
  44. package/src/commands/audit/auditController.ts +0 -11
  45. package/src/commands/audit/help.ts +7 -24
  46. package/src/commands/audit/processAudit.ts +1 -7
  47. package/src/commands/audit/saveFile.ts +2 -2
  48. package/src/commands/scan/processScan.js +0 -1
  49. package/src/commands/scan/sca/scaAnalysis.js +28 -13
  50. package/src/common/HTTPClient.js +9 -9
  51. package/src/constants/constants.js +9 -3
  52. package/src/constants/locales.js +47 -35
  53. package/src/constants.js +12 -10
  54. package/src/index.ts +76 -66
  55. package/src/lambda/lambda.ts +5 -2
  56. package/src/lambda/types.ts +1 -0
  57. package/src/sbom/generateSbom.ts +2 -2
  58. package/src/scaAnalysis/common/formatMessage.js +8 -1
  59. package/src/scaAnalysis/common/treeUpload.js +4 -5
  60. package/src/scaAnalysis/dotnet/analysis.js +54 -0
  61. package/src/scaAnalysis/dotnet/index.js +11 -0
  62. package/src/scaAnalysis/javascript/analysis.js +6 -7
  63. package/src/scaAnalysis/javascript/index.js +23 -7
  64. package/src/scaAnalysis/php/analysis.js +15 -35
  65. package/src/scaAnalysis/php/index.js +15 -4
  66. package/src/scaAnalysis/ruby/analysis.js +2 -11
  67. package/src/scan/autoDetection.js +18 -24
  68. package/src/scan/fileUtils.js +33 -12
  69. package/src/scan/formatScanOutput.ts +3 -3
  70. package/src/scan/scanConfig.js +2 -4
  71. package/src/utils/getConfig.ts +1 -12
  72. package/dist/audit/AnalysisEngine.js +0 -37
  73. package/dist/audit/autodetection/autoDetectLanguage.js +0 -32
  74. package/dist/audit/dotnetAnalysisEngine/index.js +0 -25
  75. package/dist/audit/dotnetAnalysisEngine/parseLockFileContents.js +0 -35
  76. package/dist/audit/dotnetAnalysisEngine/parseProjectFileContents.js +0 -15
  77. package/dist/audit/dotnetAnalysisEngine/readLockFileContents.js +0 -18
  78. package/dist/audit/dotnetAnalysisEngine/readProjectFileContents.js +0 -14
  79. package/dist/audit/dotnetAnalysisEngine/sanitizer.js +0 -9
  80. package/dist/audit/goAnalysisEngine/index.js +0 -17
  81. package/dist/audit/goAnalysisEngine/parseProjectFileContents.js +0 -164
  82. package/dist/audit/goAnalysisEngine/readProjectFileContents.js +0 -21
  83. package/dist/audit/goAnalysisEngine/sanitizer.js +0 -5
  84. package/dist/audit/javaAnalysisEngine/index.js +0 -34
  85. package/dist/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +0 -155
  86. package/dist/audit/javaAnalysisEngine/parseProjectFileContents.js +0 -353
  87. package/dist/audit/javaAnalysisEngine/readProjectFileContents.js +0 -98
  88. package/dist/audit/javaAnalysisEngine/sanitizer.js +0 -5
  89. package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +0 -25
  90. package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +0 -25
  91. package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasLockFile.js +0 -35
  92. package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +0 -24
  93. package/dist/audit/languageAnalysisEngine/constants.js +0 -20
  94. package/dist/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +0 -25
  95. package/dist/audit/languageAnalysisEngine/index.js +0 -39
  96. package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +0 -66
  97. package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +0 -166
  98. package/dist/audit/nodeAnalysisEngine/handleNPMLockFileV2.js +0 -40
  99. package/dist/audit/nodeAnalysisEngine/index.js +0 -31
  100. package/dist/audit/nodeAnalysisEngine/parseNPMLockFileContents.js +0 -18
  101. package/dist/audit/nodeAnalysisEngine/parseYarnLockFileContents.js +0 -18
  102. package/dist/audit/nodeAnalysisEngine/readNPMLockFileContents.js +0 -17
  103. package/dist/audit/nodeAnalysisEngine/readProjectFileContents.js +0 -14
  104. package/dist/audit/nodeAnalysisEngine/readYarnLockFileContents.js +0 -24
  105. package/dist/audit/nodeAnalysisEngine/sanitizer.js +0 -9
  106. package/dist/audit/phpAnalysisEngine/index.js +0 -23
  107. package/dist/audit/phpAnalysisEngine/parseLockFileContents.js +0 -52
  108. package/dist/audit/phpAnalysisEngine/readLockFileContents.js +0 -13
  109. package/dist/audit/phpAnalysisEngine/readProjectFileContents.js +0 -16
  110. package/dist/audit/phpAnalysisEngine/sanitizer.js +0 -5
  111. package/dist/audit/pythonAnalysisEngine/index.js +0 -25
  112. package/dist/audit/pythonAnalysisEngine/parsePipfileLockContents.js +0 -17
  113. package/dist/audit/pythonAnalysisEngine/parseProjectFileContents.js +0 -21
  114. package/dist/audit/pythonAnalysisEngine/readPipfileLockFileContents.js +0 -13
  115. package/dist/audit/pythonAnalysisEngine/readPythonProjectFileContents.js +0 -14
  116. package/dist/audit/pythonAnalysisEngine/sanitizer.js +0 -7
  117. package/dist/audit/rubyAnalysisEngine/index.js +0 -25
  118. package/dist/audit/rubyAnalysisEngine/parseGemfileLockContents.js +0 -176
  119. package/dist/audit/rubyAnalysisEngine/parsedGemfile.js +0 -22
  120. package/dist/audit/rubyAnalysisEngine/readGemfileContents.js +0 -14
  121. package/dist/audit/rubyAnalysisEngine/readGemfileLockContents.js +0 -14
  122. package/dist/audit/rubyAnalysisEngine/sanitizer.js +0 -6
  123. package/src/audit/AnalysisEngine.js +0 -103
  124. package/src/audit/autodetection/autoDetectLanguage.ts +0 -40
  125. package/src/audit/dotnetAnalysisEngine/index.js +0 -26
  126. package/src/audit/dotnetAnalysisEngine/parseLockFileContents.js +0 -47
  127. package/src/audit/dotnetAnalysisEngine/parseProjectFileContents.js +0 -29
  128. package/src/audit/dotnetAnalysisEngine/readLockFileContents.js +0 -30
  129. package/src/audit/dotnetAnalysisEngine/readProjectFileContents.js +0 -26
  130. package/src/audit/dotnetAnalysisEngine/sanitizer.js +0 -11
  131. package/src/audit/goAnalysisEngine/index.js +0 -18
  132. package/src/audit/goAnalysisEngine/parseProjectFileContents.js +0 -209
  133. package/src/audit/goAnalysisEngine/readProjectFileContents.js +0 -31
  134. package/src/audit/goAnalysisEngine/sanitizer.js +0 -7
  135. package/src/audit/javaAnalysisEngine/index.js +0 -41
  136. package/src/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +0 -225
  137. package/src/audit/javaAnalysisEngine/parseProjectFileContents.js +0 -420
  138. package/src/audit/javaAnalysisEngine/readProjectFileContents.js +0 -141
  139. package/src/audit/javaAnalysisEngine/sanitizer.js +0 -6
  140. package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +0 -36
  141. package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +0 -42
  142. package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasLockFile.js +0 -54
  143. package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +0 -33
  144. package/src/audit/languageAnalysisEngine/constants.js +0 -23
  145. package/src/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +0 -41
  146. package/src/audit/languageAnalysisEngine/index.js +0 -45
  147. package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +0 -96
  148. package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +0 -251
  149. package/src/audit/nodeAnalysisEngine/handleNPMLockFileV2.js +0 -49
  150. package/src/audit/nodeAnalysisEngine/index.js +0 -35
  151. package/src/audit/nodeAnalysisEngine/parseNPMLockFileContents.js +0 -20
  152. package/src/audit/nodeAnalysisEngine/parseYarnLockFileContents.js +0 -26
  153. package/src/audit/nodeAnalysisEngine/readNPMLockFileContents.js +0 -23
  154. package/src/audit/nodeAnalysisEngine/readProjectFileContents.js +0 -27
  155. package/src/audit/nodeAnalysisEngine/readYarnLockFileContents.js +0 -36
  156. package/src/audit/nodeAnalysisEngine/sanitizer.js +0 -11
  157. package/src/audit/phpAnalysisEngine/index.js +0 -27
  158. package/src/audit/phpAnalysisEngine/parseLockFileContents.js +0 -60
  159. package/src/audit/phpAnalysisEngine/readLockFileContents.js +0 -14
  160. package/src/audit/phpAnalysisEngine/readProjectFileContents.js +0 -25
  161. package/src/audit/phpAnalysisEngine/sanitizer.js +0 -4
  162. package/src/audit/pythonAnalysisEngine/index.js +0 -55
  163. package/src/audit/pythonAnalysisEngine/parsePipfileLockContents.js +0 -23
  164. package/src/audit/pythonAnalysisEngine/parseProjectFileContents.js +0 -33
  165. package/src/audit/pythonAnalysisEngine/readPipfileLockFileContents.js +0 -16
  166. package/src/audit/pythonAnalysisEngine/readPythonProjectFileContents.js +0 -22
  167. package/src/audit/pythonAnalysisEngine/sanitizer.js +0 -9
  168. package/src/audit/rubyAnalysisEngine/index.js +0 -30
  169. package/src/audit/rubyAnalysisEngine/parseGemfileLockContents.js +0 -215
  170. package/src/audit/rubyAnalysisEngine/parsedGemfile.js +0 -39
  171. package/src/audit/rubyAnalysisEngine/readGemfileContents.js +0 -18
  172. package/src/audit/rubyAnalysisEngine/readGemfileLockContents.js +0 -17
  173. package/src/audit/rubyAnalysisEngine/sanitizer.js +0 -8
@@ -9,11 +9,11 @@ import { orderBy } from 'lodash'
9
9
  import chalk from 'chalk'
10
10
  import { ReportCVEModel, ReportLibraryModel } from './models/reportLibraryModel'
11
11
  import {
12
+ countVulnerableLibrariesBySeverity,
12
13
  findCVESeveritiesAndOrderByHighestPriority,
13
14
  findHighestSeverityCVE,
14
15
  findNameAndVersion,
15
- severityCountAllCVEs,
16
- severityCountAllLibraries
16
+ severityCountAllCVEs
17
17
  } from './utils/reportUtils'
18
18
  import { SeverityCountModel } from './models/severityCountModel'
19
19
  import {
@@ -28,16 +28,16 @@ import {
28
28
  MEDIUM_COLOUR,
29
29
  NOTE_COLOUR
30
30
  } from '../../../constants/constants'
31
+ import Table from 'cli-table3'
31
32
 
32
- export const createLibraryHeader = (
33
- id: string,
33
+ export const createSummaryMessage = (
34
34
  numberOfVulnerableLibraries: number,
35
35
  numberOfCves: number
36
36
  ) => {
37
37
  numberOfVulnerableLibraries === 1
38
- ? console.log(`Found 1 vulnerable library containing ${numberOfCves} CVEs`)
38
+ ? console.log(`Found 1 vulnerable library containing ${numberOfCves} CVE`)
39
39
  : console.log(
40
- `Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVEs `
40
+ `Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVEs`
41
41
  )
42
42
  }
43
43
 
@@ -59,21 +59,35 @@ export const getReport = async (config: any, reportId: string) => {
59
59
  }
60
60
 
61
61
  export const printVulnerabilityResponse = (
62
- vulnerabilities: ReportLibraryModel[],
63
- config: any
62
+ config: any,
63
+ vulnerableLibraries: ReportLibraryModel[],
64
+ numberOfVulnerableLibraries: number,
65
+ numberOfCves: number,
66
+ guidance: any
64
67
  ) => {
65
68
  let hasSomeVulnerabilitiesReported = false
66
- printFormattedOutput(vulnerabilities, config)
67
- if (Object.keys(vulnerabilities).length > 0) {
69
+ printFormattedOutput(
70
+ config,
71
+ vulnerableLibraries,
72
+ numberOfVulnerableLibraries,
73
+ numberOfCves,
74
+ guidance
75
+ )
76
+ if (Object.keys(vulnerableLibraries).length > 0) {
68
77
  hasSomeVulnerabilitiesReported = true
69
78
  }
70
79
  return hasSomeVulnerabilitiesReported
71
80
  }
72
81
 
73
82
  export const printFormattedOutput = (
83
+ config: any,
74
84
  libraries: ReportLibraryModel[],
75
- config: any
85
+ numberOfVulnerableLibraries: number,
86
+ numberOfCves: number,
87
+ guidance: any
76
88
  ) => {
89
+ createSummaryMessage(numberOfVulnerableLibraries, numberOfCves)
90
+ console.log()
77
91
  const report = new ReportList()
78
92
 
79
93
  for (const library of libraries) {
@@ -91,7 +105,6 @@ export const printFormattedOutput = (
91
105
  ),
92
106
  library.cveArray
93
107
  )
94
-
95
108
  report.reportOutputList.push(newOutputModel)
96
109
  }
97
110
 
@@ -105,17 +118,40 @@ export const printFormattedOutput = (
105
118
  return reportListItem.compositeKey.numberOfSeverities
106
119
  }
107
120
  ],
108
- ['desc']
121
+ ['asc', 'desc']
109
122
  )
110
123
 
111
- let contrastHeaderNumCounter =
112
- outputOrderedByLowestSeverityAndLowestNumOfCvesFirst.length + 1
124
+ let contrastHeaderNumCounter = 0
113
125
  for (const reportModel of outputOrderedByLowestSeverityAndLowestNumOfCvesFirst) {
114
- contrastHeaderNumCounter--
126
+ contrastHeaderNumCounter++
115
127
  const { libraryName, libraryVersion, highestSeverity } =
116
128
  reportModel.compositeKey
117
129
  const numOfCVEs = reportModel.cveArray.length
118
130
 
131
+ const table = new Table({
132
+ chars: {
133
+ top: '',
134
+ 'top-mid': '',
135
+ 'top-left': '',
136
+ 'top-right': '',
137
+ bottom: '',
138
+ 'bottom-mid': '',
139
+ 'bottom-left': '',
140
+ 'bottom-right': '',
141
+ left: '',
142
+ 'left-mid': '',
143
+ mid: '',
144
+ 'mid-mid': '',
145
+ right: '',
146
+ 'right-mid': '',
147
+ middle: ' '
148
+ },
149
+ style: { 'padding-left': 0, 'padding-right': 0 },
150
+ colAligns: ['right'],
151
+ wordWrap: true,
152
+ colWidths: [12, 1, 100]
153
+ })
154
+
119
155
  const header = buildHeader(
120
156
  highestSeverity,
121
157
  contrastHeaderNumCounter,
@@ -124,31 +160,36 @@ export const printFormattedOutput = (
124
160
  numOfCVEs
125
161
  )
126
162
 
127
- const body = buildBody(reportModel.cveArray)
163
+ const advice = gatherRemediationAdvice(guidance, reportModel)
164
+
165
+ const body = buildBody(reportModel.cveArray, advice)
128
166
 
129
167
  const reportOutputModel = new ReportOutputModel(header, body)
168
+
169
+ table.push(
170
+ reportOutputModel.body.issueMessage,
171
+ reportOutputModel.body.issueMessageCves,
172
+ reportOutputModel.body.adviceMessage
173
+ )
174
+
130
175
  console.log(
131
176
  reportOutputModel.header.vulnMessage,
132
177
  reportOutputModel.header.introducesMessage
133
178
  )
134
- console.log(reportOutputModel.body.issueMessage)
135
- console.log(reportOutputModel.body.adviceMessage + '\n')
179
+ console.log(table.toString() + '\n')
136
180
  }
137
181
 
182
+ createSummaryMessage(numberOfVulnerableLibraries, numberOfCves)
138
183
  const {
139
184
  criticalMessage,
140
185
  highMessage,
141
186
  mediumMessage,
142
187
  lowMessage,
143
- noteMessage,
144
- total
145
- } = buildFooter(libraries)
146
-
147
- if (total > 1) {
148
- console.log(
149
- `${criticalMessage} | ${highMessage} | ${mediumMessage} | ${lowMessage} | ${noteMessage}`
150
- )
151
- }
188
+ noteMessage
189
+ } = buildFooter(outputOrderedByLowestSeverityAndLowestNumOfCvesFirst)
190
+ console.log(
191
+ `${criticalMessage} | ${highMessage} | ${mediumMessage} | ${lowMessage} | ${noteMessage}`
192
+ )
152
193
  }
153
194
 
154
195
  export function buildHeader(
@@ -168,14 +209,12 @@ export function buildHeader(
168
209
  `${formattedHeaderNum} - [${highestSeverity.severity}] ${libraryName}-${version}`
169
210
  )
170
211
 
171
- const introducesMessage = chalk.bold(
172
- `introduces ${numOfCVEs} ${vulnerabilityPluralised}`
173
- )
212
+ const introducesMessage = `introduces ${numOfCVEs} ${vulnerabilityPluralised}`
174
213
 
175
214
  return new ReportOutputHeaderModel(vulnMessage, introducesMessage)
176
215
  }
177
216
 
178
- export function buildBody(cveArray: ReportCVEModel[]) {
217
+ export function buildBody(cveArray: ReportCVEModel[], advice: any) {
179
218
  const cveMessages: string[] = []
180
219
 
181
220
  findCVESeveritiesAndOrderByHighestPriority(cveArray).forEach(
@@ -187,57 +226,57 @@ export function buildBody(cveArray: ReportCVEModel[]) {
187
226
  .hex(outputColour)
188
227
  .bold(`[${severity.charAt(0).toUpperCase()}]`)
189
228
 
190
- const builtMessage = `${severityShorthand} ${cveName}`
229
+ const builtMessage = severityShorthand + cveName
191
230
  cveMessages.push(builtMessage)
192
231
  }
193
232
  )
194
233
 
195
234
  const numAndSeverityType = getNumOfAndSeverityType(cveArray)
196
235
 
197
- const issueMessage = ` ${chalk.bold(
198
- 'Issue'
199
- )} : ${numAndSeverityType} ${cveMessages.join(', ')}.`
236
+ const issueMessage = [chalk.bold('Issue'), ':', `${numAndSeverityType}`]
237
+
238
+ const issueMessageCves = ['', '', cveMessages.join(', ')]
200
239
 
201
- const adviceMessage = ` ${chalk.bold('Advice')} : ${chalk.bold(
202
- 'Update to latest version'
203
- )}.`
240
+ //todo different advice based on remediationGuidance being available or now
241
+ // console.log(advice)
204
242
 
205
- return new ReportOutputBodyModel(issueMessage, adviceMessage)
243
+ const displayAdvice = advice?.minimum
244
+ ? `Update to version ${chalk.bold(advice.minimum)}`
245
+ : `Update to latest version`
246
+
247
+ const adviceMessage = [chalk.bold('Advice'), ':', displayAdvice]
248
+
249
+ return new ReportOutputBodyModel(
250
+ issueMessage,
251
+ issueMessageCves,
252
+ adviceMessage
253
+ )
206
254
  }
207
255
 
208
- const buildFooter = (libraries: ReportLibraryModel[]) => {
209
- const { critical, high, medium, low, note, getTotal } =
210
- severityCountAllLibraries(libraries)
211
- const criticalMessage = chalk
212
- .hex(CRITICAL_COLOUR)
213
- .bold(`${critical} Critical`)
214
- const highMessage = chalk.hex(HIGH_COLOUR).bold(`${high} High`)
215
- const mediumMessage = chalk.hex(MEDIUM_COLOUR).bold(`${medium} Medium`)
216
- const lowMessage = chalk.hex(LOW_COLOUR).bold(`${low} Low`)
217
- const noteMessage = chalk.hex(NOTE_COLOUR).bold(`${note} Note`)
256
+ export function gatherRemediationAdvice(guidance: any, reportModel: any) {
257
+ const guidanceData = {
258
+ minimum: undefined,
259
+ maximum: undefined,
260
+ latest: undefined
261
+ }
218
262
 
219
- return {
220
- criticalMessage,
221
- highMessage,
222
- mediumMessage,
223
- lowMessage,
224
- noteMessage,
225
- total: getTotal
263
+ const data =
264
+ guidance[
265
+ reportModel.compositeKey.libraryName +
266
+ '@' +
267
+ reportModel.compositeKey.libraryVersion
268
+ ]
269
+
270
+ if (data) {
271
+ guidanceData.minimum = data.minUpgradeVersion
272
+ guidanceData.maximum = data.maxUpgradeVersion
226
273
  }
274
+
275
+ return guidanceData
227
276
  }
228
277
 
229
278
  export function buildFormattedHeaderNum(contrastHeaderNum: number) {
230
- let formattedHeaderNum
231
-
232
- if (contrastHeaderNum < 10) {
233
- formattedHeaderNum = `00${contrastHeaderNum}`
234
- } else if (contrastHeaderNum >= 10 && contrastHeaderNum < 100) {
235
- formattedHeaderNum = `0${contrastHeaderNum}`
236
- } else if (contrastHeaderNum >= 100) {
237
- formattedHeaderNum = contrastHeaderNum
238
- }
239
-
240
- return `CONTRAST-${formattedHeaderNum}`
279
+ return `CONTRAST-${contrastHeaderNum.toString().padStart(3, '0')}`
241
280
  }
242
281
 
243
282
  export function getNumOfAndSeverityType(cveArray: ReportCVEModel[]) {
@@ -257,3 +296,24 @@ export function getNumOfAndSeverityType(cveArray: ReportCVEModel[]) {
257
296
  .replace(/\s+/g, ' ')
258
297
  .trim()
259
298
  }
299
+
300
+ const buildFooter = (reportModelStructure: 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
+ }
@@ -19,11 +19,17 @@ export class ReportOutputHeaderModel {
19
19
  }
20
20
 
21
21
  export class ReportOutputBodyModel {
22
- issueMessage: string
23
- adviceMessage: string
22
+ issueMessage: string[]
23
+ issueMessageCves: string[]
24
+ adviceMessage: string[]
24
25
 
25
- constructor(bodyIssueMessage: string, bodyAdviceMessage: string) {
26
- this.issueMessage = bodyIssueMessage
27
- this.adviceMessage = bodyAdviceMessage
26
+ constructor(
27
+ issueMessage: string[],
28
+ issueMessageCves: string[],
29
+ adviceMessage: string[]
30
+ ) {
31
+ this.issueMessage = issueMessage
32
+ this.issueMessageCves = issueMessageCves
33
+ this.adviceMessage = adviceMessage
28
34
  }
29
35
  }
@@ -1,5 +1,4 @@
1
1
  import {
2
- createLibraryHeader,
3
2
  getReport,
4
3
  printVulnerabilityResponse
5
4
  } from './commonReportingFunctions'
@@ -9,33 +8,51 @@ import {
9
8
  } from './utils/reportUtils'
10
9
  import i18n from 'i18n'
11
10
  import chalk from 'chalk'
11
+ import * as constants from '../../../constants/constants'
12
12
 
13
- export async function vulnerabilityReport(
14
- analysis: any,
15
- applicationId: string,
16
- reportId: string
17
- ) {
18
- const reportResponse = await getReport(analysis.config, reportId)
13
+ export function convertKeysToStandardFormat(config: any, guidance: any) {
14
+ let convertedGuidance = guidance
19
15
 
20
- if (reportResponse !== undefined) {
21
- const id = applicationId
22
- formatVulnerabilityOutput(
23
- reportResponse.vulnerabilities,
24
- id,
25
- analysis.config
26
- )
16
+ switch (config.language) {
17
+ case constants.supportedLanguages.JAVA:
18
+ case constants.supportedLanguages.GO:
19
+ case constants.supportedLanguages.PHP:
20
+ break
21
+ case constants.supportedLanguages.NODE:
22
+ case constants.supportedLanguages.DOTNET:
23
+ case constants.supportedLanguages.PYTHON:
24
+ case constants.supportedLanguages.RUBY:
25
+ convertedGuidance = convertJSDotNetPython(guidance)
26
+ break
27
27
  }
28
+ return convertedGuidance
29
+ }
30
+
31
+ export function convertJSDotNetPython(guidance: any) {
32
+ const returnObject = {}
33
+
34
+ Object.entries(guidance).forEach(([key, value]) => {
35
+ const splitKey = key.split('/')
36
+ if (splitKey.length === 2) {
37
+ // @ts-ignore
38
+ returnObject[splitKey[1]] = value
39
+ }
40
+ })
41
+ return returnObject
28
42
  }
29
43
 
30
44
  export function formatVulnerabilityOutput(
31
45
  libraryVulnerabilityResponse: any,
32
46
  id: string,
33
- config: any
47
+ config: any,
48
+ remediationGuidance: any
34
49
  ) {
35
50
  const vulnerableLibraries = convertGenericToTypedLibraryVulns(
36
51
  libraryVulnerabilityResponse
37
52
  )
38
53
 
54
+ const guidance = convertKeysToStandardFormat(config, remediationGuidance)
55
+
39
56
  const numberOfVulnerableLibraries = vulnerableLibraries.length
40
57
 
41
58
  if (numberOfVulnerableLibraries === 0) {
@@ -59,11 +76,12 @@ export function formatVulnerabilityOutput(
59
76
  let numberOfCves = 0
60
77
  vulnerableLibraries.forEach(lib => (numberOfCves += lib.cveArray.length))
61
78
 
62
- createLibraryHeader(id, numberOfVulnerableLibraries, numberOfCves)
63
-
64
79
  const hasSomeVulnerabilitiesReported = printVulnerabilityResponse(
80
+ config,
65
81
  vulnerableLibraries,
66
- config
82
+ numberOfVulnerableLibraries,
83
+ numberOfCves,
84
+ guidance
67
85
  )
68
86
 
69
87
  return [
@@ -75,6 +93,7 @@ export function formatVulnerabilityOutput(
75
93
  }
76
94
 
77
95
  export async function vulnerabilityReportV2(config: any, reportId: string) {
96
+ console.log()
78
97
  const reportResponse = await getReport(config, reportId)
79
98
 
80
99
  if (reportResponse !== undefined) {
@@ -82,7 +101,10 @@ export async function vulnerabilityReportV2(config: any, reportId: string) {
82
101
  formatVulnerabilityOutput(
83
102
  reportResponse.vulnerabilities,
84
103
  config.applicationId,
85
- config
104
+ config,
105
+ reportResponse.remediationGuidance
106
+ ? reportResponse.remediationGuidance
107
+ : {}
86
108
  )
87
109
  }
88
110
  }
@@ -3,7 +3,7 @@ import {
3
3
  ReportLibraryModel
4
4
  } from '../models/reportLibraryModel'
5
5
  import { ReportSeverityModel } from '../models/reportSeverityModel'
6
- import languageAnalysisEngine from '../../../languageAnalysisEngine/constants'
6
+ import languageAnalysisEngine from './../../../../constants/constants'
7
7
  import {
8
8
  CRITICAL_COLOUR,
9
9
  CRITICAL_PRIORITY,
@@ -18,6 +18,7 @@ import {
18
18
  } from '../../../../constants/constants'
19
19
  import { orderBy } from 'lodash'
20
20
  import { SeverityCountModel } from '../models/severityCountModel'
21
+ import { ReportModelStructure } from '../models/reportListModel'
21
22
  const {
22
23
  supportedLanguages: { GO }
23
24
  } = languageAnalysisEngine
@@ -122,11 +123,49 @@ export function findNameAndVersion(library: ReportLibraryModel, config: any) {
122
123
 
123
124
  return { name, version }
124
125
  } else {
125
- const splitLibraryName = library.name.split('/')
126
- const nameVersion = splitLibraryName[1].split('@')
127
- const name = nameVersion[0]
126
+ //spreads items from split into set so no duplicates appear
127
+ const uniqueSplitLibraryName = [...new Set(library.name.split('/'))]
128
+ const nameVersion = uniqueSplitLibraryName[1].split('@')
129
+
130
+ let parentLibrary
131
+ let name
132
+ if (
133
+ uniqueSplitLibraryName[0] !== 'null' &&
134
+ uniqueSplitLibraryName[0] !== '' &&
135
+ !uniqueSplitLibraryName[1].includes(uniqueSplitLibraryName[0])
136
+ ) {
137
+ //if the parent lib (element 0) is not null, not blank and not already part of the library name
138
+ //e.g. shared-ini-file-loader-1.0.0-rc.3 is very generic - converts to @aws-sdk/shared-ini-file-loader-1.0.0-rc.3
139
+ parentLibrary = uniqueSplitLibraryName[0]
140
+ name = `${parentLibrary}/${nameVersion[0]}`
141
+ } else {
142
+ name = nameVersion[0]
143
+ }
144
+
128
145
  const version = nameVersion[1]
129
146
 
130
147
  return { name, version }
131
148
  }
132
149
  }
150
+
151
+ export function countVulnerableLibrariesBySeverity(
152
+ reportModelStructure: ReportModelStructure[]
153
+ ) {
154
+ const severityCount = new SeverityCountModel()
155
+ reportModelStructure.forEach(vuln => {
156
+ const currentSeverity = vuln.compositeKey.highestSeverity.severity
157
+ if (currentSeverity === 'CRITICAL') {
158
+ severityCount.critical += 1
159
+ } else if (currentSeverity === 'HIGH') {
160
+ severityCount.high += 1
161
+ } else if (currentSeverity === 'MEDIUM') {
162
+ severityCount.medium += 1
163
+ } else if (currentSeverity === 'LOW') {
164
+ severityCount.low += 1
165
+ } else if (currentSeverity === 'NOTE') {
166
+ severityCount.note += 1
167
+ }
168
+ })
169
+
170
+ return severityCount
171
+ }
@@ -1,5 +1,3 @@
1
- const { handleResponseErrors } = require('../../common/errorHandling')
2
- const { APP_VERSION } = require('../../constants/constants')
3
1
  const commonApi = require('../../utils/commonApi')
4
2
  const _ = require('lodash')
5
3
  const oraFunctions = require('../../utils/oraWrapper')
@@ -8,30 +6,6 @@ const oraWrapper = require('../../utils/oraWrapper')
8
6
  const requestUtils = require('../../utils/requestUtils')
9
7
  const { performance } = require('perf_hooks')
10
8
 
11
- const newSendSnapShot = async analysis => {
12
- const analysisLanguage = analysis.config.language.toLowerCase()
13
- const requestBody = {
14
- appID: analysis.config.applicationId,
15
- cliVersion: APP_VERSION,
16
- snapshot: { [analysisLanguage]: analysis[analysisLanguage] }
17
- }
18
-
19
- const client = commonApi.getHttpClient(analysis.config)
20
-
21
- return client
22
- .sendSnapshot(requestBody, analysis.config)
23
- .then(res => {
24
- if (res.statusCode === 201) {
25
- return res.body
26
- } else {
27
- handleResponseErrors(res, 'snapshot')
28
- }
29
- })
30
- .catch(err => {
31
- console.log(err)
32
- })
33
- }
34
-
35
9
  const pollSnapshotResults = async (config, snapshotId, client) => {
36
10
  await requestUtils.sleep(5000)
37
11
  return client
@@ -49,9 +23,9 @@ const getTimeout = config => {
49
23
  return config.timeout
50
24
  } else {
51
25
  if (config.verbose) {
52
- console.log('Timeout set to 2 minutes')
26
+ console.log('Timeout set to 5 minutes')
53
27
  }
54
- return 120
28
+ return 300
55
29
  }
56
30
  }
57
31
 
@@ -91,16 +65,16 @@ const pollForSnapshotCompletition = async (
91
65
  if (requestUtils.millisToSeconds(endTime) > timeout) {
92
66
  oraFunctions.failSpinner(
93
67
  reportSpinner,
94
- 'Contrast audit timed out at the specified ' + timeout + ' seconds.'
68
+ 'Contrast audit timed out at the specified timeout of ' +
69
+ timeout +
70
+ ' seconds.'
95
71
  )
96
- console.log('Please try again, allowing more time.')
97
- process.exit(1)
72
+ throw new Error('You can update the timeout using --timeout')
98
73
  }
99
74
  }
100
75
  }
101
76
  }
102
77
 
103
78
  module.exports = {
104
- newSendSnapShot: newSendSnapShot,
105
79
  pollForSnapshotCompletition: pollForSnapshotCompletition
106
80
  }
package/src/audit/save.js CHANGED
@@ -3,27 +3,43 @@ const i18n = require('i18n')
3
3
  const chalk = require('chalk')
4
4
  const save = require('../commands/audit/saveFile')
5
5
  const sbom = require('../sbom/generateSbom')
6
+ const {
7
+ SBOM_CYCLONE_DX_FILE,
8
+ SBOM_SPDX_FILE
9
+ } = require('../constants/constants')
6
10
 
7
11
  async function auditSave(config) {
8
- if (config.save) {
9
- if (config.save.toLowerCase() === 'sbom') {
10
- save.saveFile(config, await sbom.generateSbom(config))
12
+ let fileFormat
13
+ switch (config.save) {
14
+ case null:
15
+ case SBOM_CYCLONE_DX_FILE:
16
+ fileFormat = SBOM_CYCLONE_DX_FILE
17
+ break
18
+ case SBOM_SPDX_FILE:
19
+ fileFormat = SBOM_SPDX_FILE
20
+ break
21
+ default:
22
+ break
23
+ }
11
24
 
12
- const filename = `${config.applicationId}-sbom-cyclonedx.json`
13
- if (fs.existsSync(filename)) {
14
- console.log(i18n.__('auditSBOMSaveSuccess') + ` - ${filename}`)
15
- } else {
16
- console.log(
17
- chalk.yellow.bold(
18
- `\n Unable to save ${filename} Software Bill of Materials (SBOM)`
19
- )
20
- )
21
- }
25
+ if (fileFormat) {
26
+ save.saveFile(
27
+ config,
28
+ fileFormat,
29
+ await sbom.generateSbom(config, fileFormat)
30
+ )
31
+ const filename = `${config.applicationId}-sbom-${fileFormat}.json`
32
+ if (fs.existsSync(filename)) {
33
+ console.log(i18n.__('auditSBOMSaveSuccess') + ` - ${filename}`)
22
34
  } else {
23
- console.log(i18n.__('auditBadFiletypeSpecifiedForSave'))
35
+ console.log(
36
+ chalk.yellow.bold(
37
+ `\n Unable to save ${filename} Software Bill of Materials (SBOM)`
38
+ )
39
+ )
24
40
  }
25
- } else if (config.save === null) {
26
- console.log(i18n.__('auditNoFiletypeSpecifiedForSave'))
41
+ } else {
42
+ console.log(i18n.__('auditBadFiletypeSpecifiedForSave'))
27
43
  }
28
44
  }
29
45
 
@@ -1,15 +1,6 @@
1
1
  import paramHandler from '../../utils/paramsUtil/paramHandler'
2
2
  import constants from '../../constants'
3
3
  import cliOptions from '../../utils/parsedCLIOptions'
4
- import languageAnalysisEngine from '../../audit/languageAnalysisEngine/constants'
5
- import {
6
- determineProjectLanguage,
7
- identifyLanguages
8
- } from '../../audit/autodetection/autoDetectLanguage'
9
-
10
- const {
11
- supportedLanguages: { NODE, JAVASCRIPT }
12
- } = languageAnalysisEngine
13
4
 
14
5
  export const getAuditConfig = (argv: string[]): { [key: string]: string } => {
15
6
  const auditParameters = cliOptions.getCommandLineArgsCustom(
@@ -18,22 +9,6 @@ export const getAuditConfig = (argv: string[]): { [key: string]: string } => {
18
9
  )
19
10
  const paramsAuth = paramHandler.getAuth(auditParameters)
20
11
 
21
- if (
22
- auditParameters.language === undefined ||
23
- auditParameters.language === null
24
- ) {
25
- try {
26
- auditParameters.language = determineProjectLanguage(
27
- identifyLanguages(auditParameters)
28
- )
29
- } catch (err: any) {
30
- console.log(err.message)
31
- process.exit(1)
32
- }
33
- } else if (auditParameters.language.toUpperCase() === JAVASCRIPT) {
34
- auditParameters.language = NODE.toLowerCase()
35
- }
36
-
37
12
  // @ts-ignore
38
13
  return { ...paramsAuth, ...auditParameters }
39
14
  }