@contrast/contrast 1.0.8 → 1.0.11

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 (217) hide show
  1. package/README.md +2 -2
  2. package/dist/audit/languageAnalysisEngine/getProjectRootFilenames.js +16 -25
  3. package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +103 -57
  4. package/dist/audit/languageAnalysisEngine/report/models/reportGuidanceModel.js +6 -0
  5. package/dist/audit/languageAnalysisEngine/report/models/reportOutputModel.js +3 -3
  6. package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +1 -0
  7. package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +68 -17
  8. package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +39 -7
  9. package/dist/audit/languageAnalysisEngine/sendSnapshot.js +6 -30
  10. package/dist/audit/save.js +21 -13
  11. package/dist/commands/audit/auditConfig.js +3 -19
  12. package/dist/commands/audit/auditController.js +1 -10
  13. package/dist/commands/audit/help.js +7 -24
  14. package/dist/commands/audit/processAudit.js +5 -9
  15. package/dist/commands/audit/saveFile.js +2 -2
  16. package/dist/commands/auth/auth.js +1 -1
  17. package/dist/commands/config/config.js +2 -2
  18. package/dist/commands/scan/processScan.js +11 -4
  19. package/dist/commands/scan/sca/scaAnalysis.js +37 -13
  20. package/dist/common/HTTPClient.js +17 -8
  21. package/dist/common/errorHandling.js +2 -2
  22. package/dist/common/fail.js +66 -0
  23. package/dist/common/versionChecker.js +1 -1
  24. package/dist/constants/constants.js +7 -2
  25. package/dist/constants/locales.js +40 -38
  26. package/dist/constants.js +62 -12
  27. package/dist/index.js +57 -45
  28. package/dist/lambda/lambda.js +5 -2
  29. package/dist/sbom/generateSbom.js +2 -2
  30. package/dist/scaAnalysis/common/formatMessage.js +7 -1
  31. package/dist/scaAnalysis/common/scaParserForGoAndJava.js +32 -0
  32. package/dist/scaAnalysis/common/treeUpload.js +24 -10
  33. package/dist/scaAnalysis/dotnet/analysis.js +55 -0
  34. package/dist/scaAnalysis/dotnet/index.js +10 -0
  35. package/dist/scaAnalysis/go/goAnalysis.js +8 -2
  36. package/dist/scaAnalysis/java/analysis.js +10 -6
  37. package/dist/scaAnalysis/java/index.js +7 -1
  38. package/dist/scaAnalysis/java/javaBuildDepsParser.js +19 -3
  39. package/dist/scaAnalysis/javascript/analysis.js +4 -7
  40. package/dist/scaAnalysis/javascript/index.js +16 -4
  41. package/dist/scaAnalysis/php/analysis.js +14 -33
  42. package/dist/scaAnalysis/php/index.js +11 -4
  43. package/dist/scaAnalysis/python/analysis.js +43 -5
  44. package/dist/scaAnalysis/python/index.js +7 -2
  45. package/dist/scaAnalysis/ruby/analysis.js +16 -14
  46. package/dist/scan/autoDetection.js +13 -24
  47. package/dist/scan/fileUtils.js +31 -12
  48. package/dist/scan/formatScanOutput.js +9 -8
  49. package/dist/scan/populateProjectIdAndProjectName.js +5 -0
  50. package/dist/scan/scan.js +4 -0
  51. package/dist/scan/scanConfig.js +5 -5
  52. package/dist/scan/scanResults.js +39 -3
  53. package/dist/telemetry/telemetry.js +137 -0
  54. package/dist/utils/commonApi.js +1 -1
  55. package/dist/utils/getConfig.js +3 -8
  56. package/dist/utils/parsedCLIOptions.js +3 -1
  57. package/dist/utils/requestUtils.js +7 -1
  58. package/package.json +2 -3
  59. package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +21 -57
  60. package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +155 -77
  61. package/src/audit/languageAnalysisEngine/report/models/reportGuidanceModel.ts +5 -0
  62. package/src/audit/languageAnalysisEngine/report/models/reportOutputModel.ts +5 -5
  63. package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +2 -0
  64. package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +56 -27
  65. package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +45 -6
  66. package/src/audit/languageAnalysisEngine/sendSnapshot.js +6 -32
  67. package/src/audit/save.js +32 -16
  68. package/src/commands/audit/auditConfig.ts +10 -28
  69. package/src/commands/audit/auditController.ts +0 -11
  70. package/src/commands/audit/help.ts +7 -24
  71. package/src/commands/audit/processAudit.ts +16 -8
  72. package/src/commands/audit/saveFile.ts +2 -2
  73. package/src/commands/auth/auth.js +3 -1
  74. package/src/commands/config/config.js +4 -2
  75. package/src/commands/scan/processScan.js +18 -5
  76. package/src/commands/scan/sca/scaAnalysis.js +50 -18
  77. package/src/common/HTTPClient.js +23 -9
  78. package/src/common/errorHandling.ts +2 -3
  79. package/src/common/fail.js +75 -0
  80. package/src/common/versionChecker.ts +1 -1
  81. package/src/constants/constants.js +9 -3
  82. package/src/constants/locales.js +70 -45
  83. package/src/constants.js +67 -13
  84. package/src/index.ts +91 -66
  85. package/src/lambda/lambda.ts +5 -2
  86. package/src/lambda/types.ts +1 -0
  87. package/src/sbom/generateSbom.ts +2 -2
  88. package/src/scaAnalysis/common/formatMessage.js +8 -1
  89. package/src/scaAnalysis/common/scaParserForGoAndJava.js +41 -0
  90. package/src/scaAnalysis/common/treeUpload.js +25 -11
  91. package/src/scaAnalysis/dotnet/analysis.js +72 -0
  92. package/src/scaAnalysis/dotnet/index.js +11 -0
  93. package/src/scaAnalysis/go/goAnalysis.js +9 -2
  94. package/src/scaAnalysis/java/analysis.js +11 -6
  95. package/src/scaAnalysis/java/index.js +9 -1
  96. package/src/scaAnalysis/java/javaBuildDepsParser.js +25 -6
  97. package/src/scaAnalysis/javascript/analysis.js +6 -7
  98. package/src/scaAnalysis/javascript/index.js +25 -6
  99. package/src/scaAnalysis/php/analysis.js +15 -35
  100. package/src/scaAnalysis/php/index.js +15 -4
  101. package/src/scaAnalysis/python/analysis.js +49 -5
  102. package/src/scaAnalysis/python/index.js +7 -2
  103. package/src/scaAnalysis/ruby/analysis.js +18 -15
  104. package/src/scan/autoDetection.js +14 -27
  105. package/src/scan/fileUtils.js +33 -12
  106. package/src/scan/formatScanOutput.ts +10 -8
  107. package/src/scan/populateProjectIdAndProjectName.js +5 -1
  108. package/src/scan/scan.ts +4 -0
  109. package/src/scan/scanConfig.js +7 -7
  110. package/src/scan/scanResults.js +46 -3
  111. package/src/telemetry/telemetry.ts +154 -0
  112. package/src/utils/commonApi.js +1 -1
  113. package/src/utils/getConfig.ts +5 -18
  114. package/src/utils/parsedCLIOptions.js +14 -1
  115. package/src/utils/requestUtils.js +8 -1
  116. package/dist/audit/AnalysisEngine.js +0 -37
  117. package/dist/audit/autodetection/autoDetectLanguage.js +0 -32
  118. package/dist/audit/dotnetAnalysisEngine/index.js +0 -25
  119. package/dist/audit/dotnetAnalysisEngine/parseLockFileContents.js +0 -35
  120. package/dist/audit/dotnetAnalysisEngine/parseProjectFileContents.js +0 -15
  121. package/dist/audit/dotnetAnalysisEngine/readLockFileContents.js +0 -18
  122. package/dist/audit/dotnetAnalysisEngine/readProjectFileContents.js +0 -14
  123. package/dist/audit/dotnetAnalysisEngine/sanitizer.js +0 -9
  124. package/dist/audit/goAnalysisEngine/index.js +0 -17
  125. package/dist/audit/goAnalysisEngine/parseProjectFileContents.js +0 -164
  126. package/dist/audit/goAnalysisEngine/readProjectFileContents.js +0 -21
  127. package/dist/audit/goAnalysisEngine/sanitizer.js +0 -5
  128. package/dist/audit/javaAnalysisEngine/index.js +0 -34
  129. package/dist/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +0 -155
  130. package/dist/audit/javaAnalysisEngine/parseProjectFileContents.js +0 -353
  131. package/dist/audit/javaAnalysisEngine/readProjectFileContents.js +0 -98
  132. package/dist/audit/javaAnalysisEngine/sanitizer.js +0 -5
  133. package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +0 -25
  134. package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +0 -25
  135. package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasLockFile.js +0 -35
  136. package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +0 -24
  137. package/dist/audit/languageAnalysisEngine/constants.js +0 -20
  138. package/dist/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +0 -25
  139. package/dist/audit/languageAnalysisEngine/index.js +0 -39
  140. package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +0 -66
  141. package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +0 -166
  142. package/dist/audit/nodeAnalysisEngine/handleNPMLockFileV2.js +0 -40
  143. package/dist/audit/nodeAnalysisEngine/index.js +0 -31
  144. package/dist/audit/nodeAnalysisEngine/parseNPMLockFileContents.js +0 -18
  145. package/dist/audit/nodeAnalysisEngine/parseYarnLockFileContents.js +0 -18
  146. package/dist/audit/nodeAnalysisEngine/readNPMLockFileContents.js +0 -17
  147. package/dist/audit/nodeAnalysisEngine/readProjectFileContents.js +0 -14
  148. package/dist/audit/nodeAnalysisEngine/readYarnLockFileContents.js +0 -24
  149. package/dist/audit/nodeAnalysisEngine/sanitizer.js +0 -9
  150. package/dist/audit/phpAnalysisEngine/index.js +0 -23
  151. package/dist/audit/phpAnalysisEngine/parseLockFileContents.js +0 -52
  152. package/dist/audit/phpAnalysisEngine/readLockFileContents.js +0 -13
  153. package/dist/audit/phpAnalysisEngine/readProjectFileContents.js +0 -16
  154. package/dist/audit/phpAnalysisEngine/sanitizer.js +0 -5
  155. package/dist/audit/pythonAnalysisEngine/index.js +0 -25
  156. package/dist/audit/pythonAnalysisEngine/parsePipfileLockContents.js +0 -17
  157. package/dist/audit/pythonAnalysisEngine/parseProjectFileContents.js +0 -21
  158. package/dist/audit/pythonAnalysisEngine/readPipfileLockFileContents.js +0 -13
  159. package/dist/audit/pythonAnalysisEngine/readPythonProjectFileContents.js +0 -14
  160. package/dist/audit/pythonAnalysisEngine/sanitizer.js +0 -7
  161. package/dist/audit/rubyAnalysisEngine/index.js +0 -25
  162. package/dist/audit/rubyAnalysisEngine/parseGemfileLockContents.js +0 -176
  163. package/dist/audit/rubyAnalysisEngine/parsedGemfile.js +0 -22
  164. package/dist/audit/rubyAnalysisEngine/readGemfileContents.js +0 -14
  165. package/dist/audit/rubyAnalysisEngine/readGemfileLockContents.js +0 -14
  166. package/dist/audit/rubyAnalysisEngine/sanitizer.js +0 -6
  167. package/src/audit/AnalysisEngine.js +0 -103
  168. package/src/audit/autodetection/autoDetectLanguage.ts +0 -40
  169. package/src/audit/dotnetAnalysisEngine/index.js +0 -26
  170. package/src/audit/dotnetAnalysisEngine/parseLockFileContents.js +0 -47
  171. package/src/audit/dotnetAnalysisEngine/parseProjectFileContents.js +0 -29
  172. package/src/audit/dotnetAnalysisEngine/readLockFileContents.js +0 -30
  173. package/src/audit/dotnetAnalysisEngine/readProjectFileContents.js +0 -26
  174. package/src/audit/dotnetAnalysisEngine/sanitizer.js +0 -11
  175. package/src/audit/goAnalysisEngine/index.js +0 -18
  176. package/src/audit/goAnalysisEngine/parseProjectFileContents.js +0 -209
  177. package/src/audit/goAnalysisEngine/readProjectFileContents.js +0 -31
  178. package/src/audit/goAnalysisEngine/sanitizer.js +0 -7
  179. package/src/audit/javaAnalysisEngine/index.js +0 -41
  180. package/src/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +0 -225
  181. package/src/audit/javaAnalysisEngine/parseProjectFileContents.js +0 -420
  182. package/src/audit/javaAnalysisEngine/readProjectFileContents.js +0 -141
  183. package/src/audit/javaAnalysisEngine/sanitizer.js +0 -6
  184. package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +0 -36
  185. package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +0 -42
  186. package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasLockFile.js +0 -54
  187. package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +0 -33
  188. package/src/audit/languageAnalysisEngine/constants.js +0 -23
  189. package/src/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +0 -41
  190. package/src/audit/languageAnalysisEngine/index.js +0 -45
  191. package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +0 -96
  192. package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +0 -251
  193. package/src/audit/nodeAnalysisEngine/handleNPMLockFileV2.js +0 -49
  194. package/src/audit/nodeAnalysisEngine/index.js +0 -35
  195. package/src/audit/nodeAnalysisEngine/parseNPMLockFileContents.js +0 -20
  196. package/src/audit/nodeAnalysisEngine/parseYarnLockFileContents.js +0 -26
  197. package/src/audit/nodeAnalysisEngine/readNPMLockFileContents.js +0 -23
  198. package/src/audit/nodeAnalysisEngine/readProjectFileContents.js +0 -27
  199. package/src/audit/nodeAnalysisEngine/readYarnLockFileContents.js +0 -36
  200. package/src/audit/nodeAnalysisEngine/sanitizer.js +0 -11
  201. package/src/audit/phpAnalysisEngine/index.js +0 -27
  202. package/src/audit/phpAnalysisEngine/parseLockFileContents.js +0 -60
  203. package/src/audit/phpAnalysisEngine/readLockFileContents.js +0 -14
  204. package/src/audit/phpAnalysisEngine/readProjectFileContents.js +0 -25
  205. package/src/audit/phpAnalysisEngine/sanitizer.js +0 -4
  206. package/src/audit/pythonAnalysisEngine/index.js +0 -55
  207. package/src/audit/pythonAnalysisEngine/parsePipfileLockContents.js +0 -23
  208. package/src/audit/pythonAnalysisEngine/parseProjectFileContents.js +0 -33
  209. package/src/audit/pythonAnalysisEngine/readPipfileLockFileContents.js +0 -16
  210. package/src/audit/pythonAnalysisEngine/readPythonProjectFileContents.js +0 -22
  211. package/src/audit/pythonAnalysisEngine/sanitizer.js +0 -9
  212. package/src/audit/rubyAnalysisEngine/index.js +0 -30
  213. package/src/audit/rubyAnalysisEngine/parseGemfileLockContents.js +0 -215
  214. package/src/audit/rubyAnalysisEngine/parsedGemfile.js +0 -39
  215. package/src/audit/rubyAnalysisEngine/readGemfileContents.js +0 -18
  216. package/src/audit/rubyAnalysisEngine/readGemfileLockContents.js +0 -17
  217. 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,17 @@ import {
28
28
  MEDIUM_COLOUR,
29
29
  NOTE_COLOUR
30
30
  } from '../../../constants/constants'
31
+ import Table from 'cli-table3'
32
+ import { ReportGuidanceModel } from './models/reportGuidanceModel'
31
33
 
32
- export const createLibraryHeader = (
33
- id: string,
34
+ export const createSummaryMessage = (
34
35
  numberOfVulnerableLibraries: number,
35
36
  numberOfCves: number
36
37
  ) => {
37
38
  numberOfVulnerableLibraries === 1
38
- ? console.log(`Found 1 vulnerable library containing ${numberOfCves} CVEs`)
39
+ ? console.log(`Found 1 vulnerable library containing ${numberOfCves} CVE`)
39
40
  : console.log(
40
- `Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVEs `
41
+ `Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVEs`
41
42
  )
42
43
  }
43
44
 
@@ -59,21 +60,35 @@ export const getReport = async (config: any, reportId: string) => {
59
60
  }
60
61
 
61
62
  export const printVulnerabilityResponse = (
62
- vulnerabilities: ReportLibraryModel[],
63
- config: any
63
+ config: any,
64
+ vulnerableLibraries: ReportLibraryModel[],
65
+ numberOfVulnerableLibraries: number,
66
+ numberOfCves: number,
67
+ guidance: any
64
68
  ) => {
65
69
  let hasSomeVulnerabilitiesReported = false
66
- printFormattedOutput(vulnerabilities, config)
67
- if (Object.keys(vulnerabilities).length > 0) {
70
+ printFormattedOutput(
71
+ config,
72
+ vulnerableLibraries,
73
+ numberOfVulnerableLibraries,
74
+ numberOfCves,
75
+ guidance
76
+ )
77
+ if (Object.keys(vulnerableLibraries).length > 0) {
68
78
  hasSomeVulnerabilitiesReported = true
69
79
  }
70
80
  return hasSomeVulnerabilitiesReported
71
81
  }
72
82
 
73
83
  export const printFormattedOutput = (
84
+ config: any,
74
85
  libraries: ReportLibraryModel[],
75
- config: any
86
+ numberOfVulnerableLibraries: number,
87
+ numberOfCves: number,
88
+ guidance: any
76
89
  ) => {
90
+ createSummaryMessage(numberOfVulnerableLibraries, numberOfCves)
91
+ console.log()
77
92
  const report = new ReportList()
78
93
 
79
94
  for (const library of libraries) {
@@ -91,7 +106,6 @@ export const printFormattedOutput = (
91
106
  ),
92
107
  library.cveArray
93
108
  )
94
-
95
109
  report.reportOutputList.push(newOutputModel)
96
110
  }
97
111
 
@@ -105,17 +119,40 @@ export const printFormattedOutput = (
105
119
  return reportListItem.compositeKey.numberOfSeverities
106
120
  }
107
121
  ],
108
- ['desc']
122
+ ['asc', 'desc']
109
123
  )
110
124
 
111
- let contrastHeaderNumCounter =
112
- outputOrderedByLowestSeverityAndLowestNumOfCvesFirst.length + 1
125
+ let contrastHeaderNumCounter = 0
113
126
  for (const reportModel of outputOrderedByLowestSeverityAndLowestNumOfCvesFirst) {
114
- contrastHeaderNumCounter--
127
+ contrastHeaderNumCounter++
115
128
  const { libraryName, libraryVersion, highestSeverity } =
116
129
  reportModel.compositeKey
117
130
  const numOfCVEs = reportModel.cveArray.length
118
131
 
132
+ const table = new Table({
133
+ chars: {
134
+ top: '',
135
+ 'top-mid': '',
136
+ 'top-left': '',
137
+ 'top-right': '',
138
+ bottom: '',
139
+ 'bottom-mid': '',
140
+ 'bottom-left': '',
141
+ 'bottom-right': '',
142
+ left: '',
143
+ 'left-mid': '',
144
+ mid: '',
145
+ 'mid-mid': '',
146
+ right: '',
147
+ 'right-mid': '',
148
+ middle: ' '
149
+ },
150
+ style: { 'padding-left': 0, 'padding-right': 0 },
151
+ colAligns: ['right'],
152
+ wordWrap: true,
153
+ colWidths: [12, 1, 100]
154
+ })
155
+
119
156
  const header = buildHeader(
120
157
  highestSeverity,
121
158
  contrastHeaderNumCounter,
@@ -124,31 +161,39 @@ export const printFormattedOutput = (
124
161
  numOfCVEs
125
162
  )
126
163
 
127
- const body = buildBody(reportModel.cveArray)
164
+ const advice = gatherRemediationAdvice(
165
+ guidance,
166
+ libraryName,
167
+ libraryVersion
168
+ )
169
+
170
+ const body = buildBody(reportModel.cveArray, advice)
128
171
 
129
172
  const reportOutputModel = new ReportOutputModel(header, body)
173
+
174
+ table.push(
175
+ reportOutputModel.body.issueMessage,
176
+ reportOutputModel.body.adviceMessage
177
+ )
178
+
130
179
  console.log(
131
180
  reportOutputModel.header.vulnMessage,
132
181
  reportOutputModel.header.introducesMessage
133
182
  )
134
- console.log(reportOutputModel.body.issueMessage)
135
- console.log(reportOutputModel.body.adviceMessage + '\n')
183
+ console.log(table.toString() + '\n')
136
184
  }
137
185
 
186
+ createSummaryMessage(numberOfVulnerableLibraries, numberOfCves)
138
187
  const {
139
188
  criticalMessage,
140
189
  highMessage,
141
190
  mediumMessage,
142
191
  lowMessage,
143
- noteMessage,
144
- total
145
- } = buildFooter(libraries)
146
-
147
- if (total > 1) {
148
- console.log(
149
- `${criticalMessage} | ${highMessage} | ${mediumMessage} | ${lowMessage} | ${noteMessage}`
150
- )
151
- }
192
+ noteMessage
193
+ } = buildFooter(outputOrderedByLowestSeverityAndLowestNumOfCvesFirst)
194
+ console.log(
195
+ `${criticalMessage} | ${highMessage} | ${mediumMessage} | ${lowMessage} | ${noteMessage}`
196
+ )
152
197
  }
153
198
 
154
199
  export function buildHeader(
@@ -162,20 +207,22 @@ export function buildHeader(
162
207
  numOfCVEs > 1 ? 'vulnerabilities' : 'vulnerability'
163
208
  const formattedHeaderNum = buildFormattedHeaderNum(contrastHeaderNum)
164
209
 
165
- const vulnMessage = chalk
166
- .hex(highestSeverity.outputColour)
167
- .bold(
168
- `${formattedHeaderNum} - [${highestSeverity.severity}] ${libraryName}-${version}`
169
- )
170
-
171
- const introducesMessage = chalk.bold(
172
- `introduces ${numOfCVEs} ${vulnerabilityPluralised}`
210
+ const headerColour = chalk.hex(highestSeverity.outputColour)
211
+ const headerNumAndSeverity = headerColour(
212
+ `${formattedHeaderNum} - [${highestSeverity.severity}]`
173
213
  )
214
+ const libraryNameAndVersion = headerColour.bold(`${libraryName}-${version}`)
215
+ const vulnMessage = `${headerNumAndSeverity} ${libraryNameAndVersion}`
216
+
217
+ const introducesMessage = `introduces ${numOfCVEs} ${vulnerabilityPluralised}`
174
218
 
175
219
  return new ReportOutputHeaderModel(vulnMessage, introducesMessage)
176
220
  }
177
221
 
178
- export function buildBody(cveArray: ReportCVEModel[]) {
222
+ export function buildBody(
223
+ cveArray: ReportCVEModel[],
224
+ advice: ReportGuidanceModel
225
+ ) {
179
226
  const cveMessages: string[] = []
180
227
 
181
228
  findCVESeveritiesAndOrderByHighestPriority(cveArray).forEach(
@@ -187,57 +234,51 @@ export function buildBody(cveArray: ReportCVEModel[]) {
187
234
  .hex(outputColour)
188
235
  .bold(`[${severity.charAt(0).toUpperCase()}]`)
189
236
 
190
- const builtMessage = `${severityShorthand} ${cveName}`
237
+ const builtMessage = severityShorthand + cveName
191
238
  cveMessages.push(builtMessage)
192
239
  }
193
240
  )
194
241
 
195
242
  const numAndSeverityType = getNumOfAndSeverityType(cveArray)
196
243
 
197
- const issueMessage = ` ${chalk.bold(
198
- 'Issue'
199
- )} : ${numAndSeverityType} ${cveMessages.join(', ')}.`
244
+ const issueMessage = [
245
+ chalk.bold('Issue'),
246
+ ':',
247
+ `${numAndSeverityType} ${cveMessages.join(', ')}`
248
+ ]
249
+
250
+ //todo different advice based on remediationGuidance being available or now
251
+ // console.log(advice)
252
+
253
+ const minOrMax = advice.maximum ? advice.maximum : advice.minimum
254
+ const displayAdvice = minOrMax
255
+ ? `Change to version ${chalk.bold(minOrMax)}`
256
+ : 'No recommendation is available according to our data. Upgrade to the latest stable is the best advice we can give.'
200
257
 
201
- const adviceMessage = ` ${chalk.bold('Advice')} : ${chalk.bold(
202
- 'Update to latest version'
203
- )}.`
258
+ const adviceMessage = [chalk.bold('Advice'), ':', displayAdvice]
204
259
 
205
260
  return new ReportOutputBodyModel(issueMessage, adviceMessage)
206
261
  }
207
262
 
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`)
263
+ export function gatherRemediationAdvice(
264
+ guidance: any,
265
+ libraryName: string,
266
+ libraryVersion: string
267
+ ) {
268
+ const guidanceModel = new ReportGuidanceModel()
218
269
 
219
- return {
220
- criticalMessage,
221
- highMessage,
222
- mediumMessage,
223
- lowMessage,
224
- noteMessage,
225
- total: getTotal
270
+ const data = guidance[libraryName + '@' + libraryVersion]
271
+
272
+ if (data) {
273
+ guidanceModel.minimum = data.minUpgradeVersion
274
+ guidanceModel.maximum = data.maxUpgradeVersion
226
275
  }
276
+
277
+ return guidanceModel
227
278
  }
228
279
 
229
280
  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}`
281
+ return `CONTRAST-${contrastHeaderNum.toString().padStart(3, '0')}`
241
282
  }
242
283
 
243
284
  export function getNumOfAndSeverityType(cveArray: ReportCVEModel[]) {
@@ -246,14 +287,51 @@ export function getNumOfAndSeverityType(cveArray: ReportCVEModel[]) {
246
287
  new SeverityCountModel()
247
288
  )
248
289
 
249
- const criticalMessage = critical > 0 ? `${critical} Critical` : ''
250
- const highMessage = high > 0 ? `${high} High` : ''
251
- const mediumMessage = medium > 0 ? `${medium} Medium` : ''
252
- const lowMessage = low > 0 ? `${low} Low` : ''
253
- const noteMessage = note > 0 ? `${note} Note` : ''
290
+ const criticalNumCheck = critical > 0
291
+
292
+ const highNumCheck = high > 0
293
+ const highDivider = highNumCheck ? '|' : ''
294
+
295
+ const mediumNumCheck = medium > 0
296
+ const mediumDivider = mediumNumCheck ? '|' : ''
297
+
298
+ const lowNumCheck = low > 0
299
+ const lowDivider = lowNumCheck ? '|' : ''
300
+
301
+ const noteNumCheck = low > 0
302
+ const noteDivider = noteNumCheck ? '|' : ''
303
+
304
+ const criticalMessage = criticalNumCheck
305
+ ? `${critical} Critical ${highDivider}`
306
+ : ''
307
+ const highMessage = highNumCheck ? `${high} High ${mediumDivider}` : ''
308
+ const mediumMessage = mediumNumCheck ? `${medium} Medium ${lowDivider}` : ''
309
+ const lowMessage = lowNumCheck ? `${low} Low ${noteDivider}` : ''
310
+ const noteMessage = noteNumCheck ? `${note} Note` : ''
254
311
 
255
312
  //removes/trims whitespace to single spaces
256
313
  return `${criticalMessage} ${highMessage} ${mediumMessage} ${lowMessage} ${noteMessage}`
257
314
  .replace(/\s+/g, ' ')
258
315
  .trim()
259
316
  }
317
+
318
+ const buildFooter = (reportModelStructure: ReportModelStructure[]) => {
319
+ const { critical, high, medium, low, note } =
320
+ countVulnerableLibrariesBySeverity(reportModelStructure)
321
+
322
+ const criticalMessage = chalk
323
+ .hex(CRITICAL_COLOUR)
324
+ .bold(`${critical} Critical`)
325
+ const highMessage = chalk.hex(HIGH_COLOUR).bold(`${high} High`)
326
+ const mediumMessage = chalk.hex(MEDIUM_COLOUR).bold(`${medium} Medium`)
327
+ const lowMessage = chalk.hex(LOW_COLOUR).bold(`${low} Low`)
328
+ const noteMessage = chalk.hex(NOTE_COLOUR).bold(`${note} Note`)
329
+
330
+ return {
331
+ criticalMessage,
332
+ highMessage,
333
+ mediumMessage,
334
+ lowMessage,
335
+ noteMessage
336
+ }
337
+ }
@@ -0,0 +1,5 @@
1
+ export class ReportGuidanceModel {
2
+ minimum?: string
3
+ maximum?: string
4
+ latest?: string
5
+ }
@@ -19,11 +19,11 @@ export class ReportOutputHeaderModel {
19
19
  }
20
20
 
21
21
  export class ReportOutputBodyModel {
22
- issueMessage: string
23
- adviceMessage: string
22
+ issueMessage: string[]
23
+ adviceMessage: string[]
24
24
 
25
- constructor(bodyIssueMessage: string, bodyAdviceMessage: string) {
26
- this.issueMessage = bodyIssueMessage
27
- this.adviceMessage = bodyAdviceMessage
25
+ constructor(issueMessage: string[], adviceMessage: string[]) {
26
+ this.issueMessage = issueMessage
27
+ this.adviceMessage = adviceMessage
28
28
  }
29
29
  }
@@ -4,6 +4,7 @@ export class SeverityCountModel {
4
4
  medium!: number
5
5
  low!: number
6
6
  note!: number
7
+ total!: number
7
8
 
8
9
  //needed as default to stop NaN when new object constructed
9
10
  constructor() {
@@ -12,6 +13,7 @@ export class SeverityCountModel {
12
13
  this.medium = 0
13
14
  this.low = 0
14
15
  this.note = 0
16
+ this.total = 0
15
17
  }
16
18
 
17
19
  get getTotal(): number {
@@ -1,5 +1,4 @@
1
1
  import {
2
- createLibraryHeader,
3
2
  getReport,
4
3
  printVulnerabilityResponse
5
4
  } from './commonReportingFunctions'
@@ -9,33 +8,53 @@ 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
+ import { SeverityCountModel } from './models/severityCountModel'
13
+ import * as common from '../../../common/fail'
12
14
 
13
- export async function vulnerabilityReport(
14
- analysis: any,
15
- applicationId: string,
16
- reportId: string
17
- ) {
18
- const reportResponse = await getReport(analysis.config, reportId)
15
+ export function convertKeysToStandardFormat(config: any, guidance: any) {
16
+ let convertedGuidance = guidance
19
17
 
20
- if (reportResponse !== undefined) {
21
- const id = applicationId
22
- formatVulnerabilityOutput(
23
- reportResponse.vulnerabilities,
24
- id,
25
- analysis.config
26
- )
18
+ switch (config.language) {
19
+ case constants.supportedLanguages.JAVA:
20
+ case constants.supportedLanguages.GO:
21
+ case constants.supportedLanguages.PHP:
22
+ break
23
+ case constants.supportedLanguages.NODE:
24
+ case constants.supportedLanguages.DOTNET:
25
+ case constants.supportedLanguages.PYTHON:
26
+ case constants.supportedLanguages.RUBY:
27
+ convertedGuidance = convertJSDotNetPython(guidance)
28
+ break
27
29
  }
30
+ return convertedGuidance
31
+ }
32
+
33
+ export function convertJSDotNetPython(guidance: any) {
34
+ const returnObject = {}
35
+
36
+ Object.entries(guidance).forEach(([key, value]) => {
37
+ const splitKey = key.split('/')
38
+ if (splitKey.length === 2) {
39
+ // @ts-ignore
40
+ returnObject[splitKey[1]] = value
41
+ }
42
+ })
43
+ return returnObject
28
44
  }
29
45
 
30
46
  export function formatVulnerabilityOutput(
31
47
  libraryVulnerabilityResponse: any,
32
48
  id: string,
33
- config: any
49
+ config: any,
50
+ remediationGuidance: any
34
51
  ) {
35
52
  const vulnerableLibraries = convertGenericToTypedLibraryVulns(
36
53
  libraryVulnerabilityResponse
37
54
  )
38
55
 
56
+ const guidance = convertKeysToStandardFormat(config, remediationGuidance)
57
+
39
58
  const numberOfVulnerableLibraries = vulnerableLibraries.length
40
59
 
41
60
  if (numberOfVulnerableLibraries === 0) {
@@ -55,34 +74,44 @@ export function formatVulnerabilityOutput(
55
74
  String(0)
56
75
  )
57
76
  )
77
+ return [false, 0, [new SeverityCountModel()]]
58
78
  } else {
59
79
  let numberOfCves = 0
60
80
  vulnerableLibraries.forEach(lib => (numberOfCves += lib.cveArray.length))
61
81
 
62
- createLibraryHeader(id, numberOfVulnerableLibraries, numberOfCves)
63
-
64
82
  const hasSomeVulnerabilitiesReported = printVulnerabilityResponse(
83
+ config,
65
84
  vulnerableLibraries,
66
- config
67
- )
68
-
69
- return [
70
- hasSomeVulnerabilitiesReported,
85
+ numberOfVulnerableLibraries,
71
86
  numberOfCves,
72
- severityCountAllLibraries(vulnerableLibraries)
73
- ]
87
+ guidance
88
+ )
89
+ let severityCount = new SeverityCountModel()
90
+ severityCount = severityCountAllLibraries(
91
+ vulnerableLibraries,
92
+ severityCount
93
+ )
94
+ severityCount.total = severityCount.getTotal
95
+ return [hasSomeVulnerabilitiesReported, numberOfCves, severityCount]
74
96
  }
75
97
  }
76
98
 
77
99
  export async function vulnerabilityReportV2(config: any, reportId: string) {
100
+ console.log()
78
101
  const reportResponse = await getReport(config, reportId)
79
102
 
80
103
  if (reportResponse !== undefined) {
81
- const name = config.applicationName
82
- formatVulnerabilityOutput(
104
+ let output = formatVulnerabilityOutput(
83
105
  reportResponse.vulnerabilities,
84
106
  config.applicationId,
85
- config
107
+ config,
108
+ reportResponse.remediationGuidance
109
+ ? reportResponse.remediationGuidance
110
+ : {}
86
111
  )
112
+
113
+ if (config.fail) {
114
+ common.processFail(config, output[2])
115
+ }
87
116
  }
88
117
  }
@@ -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
@@ -74,9 +75,9 @@ export function convertGenericToTypedLibraryVulns(libraries: any) {
74
75
  }
75
76
 
76
77
  export function severityCountAllLibraries(
77
- vulnerableLibraries: ReportLibraryModel[]
78
+ vulnerableLibraries: ReportLibraryModel[],
79
+ severityCount: SeverityCountModel
78
80
  ) {
79
- const severityCount = new SeverityCountModel()
80
81
  vulnerableLibraries.forEach(lib =>
81
82
  severityCountAllCVEs(lib.cveArray, severityCount)
82
83
  )
@@ -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
  }