@contrast/contrast 1.0.10 → 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 (78) hide show
  1. package/README.md +1 -1
  2. package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +39 -28
  3. package/dist/audit/languageAnalysisEngine/report/models/reportGuidanceModel.js +6 -0
  4. package/dist/audit/languageAnalysisEngine/report/models/reportOutputModel.js +1 -2
  5. package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +1 -0
  6. package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +11 -7
  7. package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +1 -2
  8. package/dist/commands/audit/auditConfig.js +3 -3
  9. package/dist/commands/audit/processAudit.js +4 -2
  10. package/dist/commands/auth/auth.js +1 -1
  11. package/dist/commands/config/config.js +2 -2
  12. package/dist/commands/scan/processScan.js +11 -4
  13. package/dist/commands/scan/sca/scaAnalysis.js +10 -3
  14. package/dist/common/HTTPClient.js +9 -0
  15. package/dist/common/fail.js +66 -0
  16. package/dist/common/versionChecker.js +1 -1
  17. package/dist/constants/constants.js +1 -1
  18. package/dist/constants/locales.js +6 -3
  19. package/dist/constants.js +39 -1
  20. package/dist/index.js +5 -2
  21. package/dist/scaAnalysis/common/scaParserForGoAndJava.js +32 -0
  22. package/dist/scaAnalysis/common/treeUpload.js +20 -5
  23. package/dist/scaAnalysis/dotnet/analysis.js +15 -3
  24. package/dist/scaAnalysis/go/goAnalysis.js +8 -2
  25. package/dist/scaAnalysis/java/analysis.js +10 -6
  26. package/dist/scaAnalysis/java/index.js +7 -1
  27. package/dist/scaAnalysis/java/javaBuildDepsParser.js +19 -3
  28. package/dist/scaAnalysis/python/analysis.js +43 -5
  29. package/dist/scaAnalysis/python/index.js +7 -2
  30. package/dist/scaAnalysis/ruby/analysis.js +14 -4
  31. package/dist/scan/formatScanOutput.js +6 -5
  32. package/dist/scan/populateProjectIdAndProjectName.js +5 -0
  33. package/dist/scan/scan.js +4 -0
  34. package/dist/scan/scanConfig.js +3 -3
  35. package/dist/scan/scanResults.js +39 -3
  36. package/dist/telemetry/telemetry.js +137 -0
  37. package/dist/utils/getConfig.js +2 -2
  38. package/dist/utils/parsedCLIOptions.js +3 -1
  39. package/dist/utils/requestUtils.js +7 -1
  40. package/package.json +1 -1
  41. package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +57 -39
  42. package/src/audit/languageAnalysisEngine/report/models/reportGuidanceModel.ts +5 -0
  43. package/src/audit/languageAnalysisEngine/report/models/reportOutputModel.ts +1 -7
  44. package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +2 -0
  45. package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +15 -8
  46. package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +2 -2
  47. package/src/commands/audit/auditConfig.ts +10 -3
  48. package/src/commands/audit/processAudit.ts +16 -2
  49. package/src/commands/auth/auth.js +3 -1
  50. package/src/commands/config/config.js +4 -2
  51. package/src/commands/scan/processScan.js +18 -4
  52. package/src/commands/scan/sca/scaAnalysis.js +11 -3
  53. package/src/common/HTTPClient.js +14 -0
  54. package/src/common/fail.js +75 -0
  55. package/src/common/versionChecker.ts +1 -1
  56. package/src/constants/constants.js +1 -1
  57. package/src/constants/locales.js +8 -4
  58. package/src/constants.js +43 -1
  59. package/src/index.ts +17 -2
  60. package/src/scaAnalysis/common/scaParserForGoAndJava.js +41 -0
  61. package/src/scaAnalysis/common/treeUpload.js +21 -6
  62. package/src/scaAnalysis/dotnet/analysis.js +21 -3
  63. package/src/scaAnalysis/go/goAnalysis.js +9 -2
  64. package/src/scaAnalysis/java/analysis.js +11 -6
  65. package/src/scaAnalysis/java/index.js +9 -1
  66. package/src/scaAnalysis/java/javaBuildDepsParser.js +25 -6
  67. package/src/scaAnalysis/python/analysis.js +49 -5
  68. package/src/scaAnalysis/python/index.js +7 -2
  69. package/src/scaAnalysis/ruby/analysis.js +16 -4
  70. package/src/scan/formatScanOutput.ts +7 -5
  71. package/src/scan/populateProjectIdAndProjectName.js +5 -1
  72. package/src/scan/scan.ts +4 -0
  73. package/src/scan/scanConfig.js +5 -3
  74. package/src/scan/scanResults.js +46 -3
  75. package/src/telemetry/telemetry.ts +154 -0
  76. package/src/utils/getConfig.ts +4 -6
  77. package/src/utils/parsedCLIOptions.js +14 -1
  78. package/src/utils/requestUtils.js +8 -1
@@ -29,6 +29,7 @@ import {
29
29
  NOTE_COLOUR
30
30
  } from '../../../constants/constants'
31
31
  import Table from 'cli-table3'
32
+ import { ReportGuidanceModel } from './models/reportGuidanceModel'
32
33
 
33
34
  export const createSummaryMessage = (
34
35
  numberOfVulnerableLibraries: number,
@@ -160,7 +161,11 @@ export const printFormattedOutput = (
160
161
  numOfCVEs
161
162
  )
162
163
 
163
- const advice = gatherRemediationAdvice(guidance, reportModel)
164
+ const advice = gatherRemediationAdvice(
165
+ guidance,
166
+ libraryName,
167
+ libraryVersion
168
+ )
164
169
 
165
170
  const body = buildBody(reportModel.cveArray, advice)
166
171
 
@@ -168,7 +173,6 @@ export const printFormattedOutput = (
168
173
 
169
174
  table.push(
170
175
  reportOutputModel.body.issueMessage,
171
- reportOutputModel.body.issueMessageCves,
172
176
  reportOutputModel.body.adviceMessage
173
177
  )
174
178
 
@@ -203,18 +207,22 @@ export function buildHeader(
203
207
  numOfCVEs > 1 ? 'vulnerabilities' : 'vulnerability'
204
208
  const formattedHeaderNum = buildFormattedHeaderNum(contrastHeaderNum)
205
209
 
206
- const vulnMessage = chalk
207
- .hex(highestSeverity.outputColour)
208
- .bold(
209
- `${formattedHeaderNum} - [${highestSeverity.severity}] ${libraryName}-${version}`
210
- )
210
+ const headerColour = chalk.hex(highestSeverity.outputColour)
211
+ const headerNumAndSeverity = headerColour(
212
+ `${formattedHeaderNum} - [${highestSeverity.severity}]`
213
+ )
214
+ const libraryNameAndVersion = headerColour.bold(`${libraryName}-${version}`)
215
+ const vulnMessage = `${headerNumAndSeverity} ${libraryNameAndVersion}`
211
216
 
212
217
  const introducesMessage = `introduces ${numOfCVEs} ${vulnerabilityPluralised}`
213
218
 
214
219
  return new ReportOutputHeaderModel(vulnMessage, introducesMessage)
215
220
  }
216
221
 
217
- export function buildBody(cveArray: ReportCVEModel[], advice: any) {
222
+ export function buildBody(
223
+ cveArray: ReportCVEModel[],
224
+ advice: ReportGuidanceModel
225
+ ) {
218
226
  const cveMessages: string[] = []
219
227
 
220
228
  findCVESeveritiesAndOrderByHighestPriority(cveArray).forEach(
@@ -233,46 +241,40 @@ export function buildBody(cveArray: ReportCVEModel[], advice: any) {
233
241
 
234
242
  const numAndSeverityType = getNumOfAndSeverityType(cveArray)
235
243
 
236
- const issueMessage = [chalk.bold('Issue'), ':', `${numAndSeverityType}`]
237
-
238
- const issueMessageCves = ['', '', cveMessages.join(', ')]
244
+ const issueMessage = [
245
+ chalk.bold('Issue'),
246
+ ':',
247
+ `${numAndSeverityType} ${cveMessages.join(', ')}`
248
+ ]
239
249
 
240
250
  //todo different advice based on remediationGuidance being available or now
241
251
  // console.log(advice)
242
252
 
243
- const displayAdvice = advice?.minimum
244
- ? `Update to version ${chalk.bold(advice.minimum)}`
245
- : `Update to latest version`
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.'
246
257
 
247
258
  const adviceMessage = [chalk.bold('Advice'), ':', displayAdvice]
248
259
 
249
- return new ReportOutputBodyModel(
250
- issueMessage,
251
- issueMessageCves,
252
- adviceMessage
253
- )
260
+ return new ReportOutputBodyModel(issueMessage, adviceMessage)
254
261
  }
255
262
 
256
- export function gatherRemediationAdvice(guidance: any, reportModel: any) {
257
- const guidanceData = {
258
- minimum: undefined,
259
- maximum: undefined,
260
- latest: undefined
261
- }
263
+ export function gatherRemediationAdvice(
264
+ guidance: any,
265
+ libraryName: string,
266
+ libraryVersion: string
267
+ ) {
268
+ const guidanceModel = new ReportGuidanceModel()
262
269
 
263
- const data =
264
- guidance[
265
- reportModel.compositeKey.libraryName +
266
- '@' +
267
- reportModel.compositeKey.libraryVersion
268
- ]
270
+ const data = guidance[libraryName + '@' + libraryVersion]
269
271
 
270
272
  if (data) {
271
- guidanceData.minimum = data.minUpgradeVersion
272
- guidanceData.maximum = data.maxUpgradeVersion
273
+ guidanceModel.minimum = data.minUpgradeVersion
274
+ guidanceModel.maximum = data.maxUpgradeVersion
273
275
  }
274
276
 
275
- return guidanceData
277
+ return guidanceModel
276
278
  }
277
279
 
278
280
  export function buildFormattedHeaderNum(contrastHeaderNum: number) {
@@ -285,11 +287,27 @@ export function getNumOfAndSeverityType(cveArray: ReportCVEModel[]) {
285
287
  new SeverityCountModel()
286
288
  )
287
289
 
288
- const criticalMessage = critical > 0 ? `${critical} Critical` : ''
289
- const highMessage = high > 0 ? `${high} High` : ''
290
- const mediumMessage = medium > 0 ? `${medium} Medium` : ''
291
- const lowMessage = low > 0 ? `${low} Low` : ''
292
- 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` : ''
293
311
 
294
312
  //removes/trims whitespace to single spaces
295
313
  return `${criticalMessage} ${highMessage} ${mediumMessage} ${lowMessage} ${noteMessage}`
@@ -0,0 +1,5 @@
1
+ export class ReportGuidanceModel {
2
+ minimum?: string
3
+ maximum?: string
4
+ latest?: string
5
+ }
@@ -20,16 +20,10 @@ export class ReportOutputHeaderModel {
20
20
 
21
21
  export class ReportOutputBodyModel {
22
22
  issueMessage: string[]
23
- issueMessageCves: string[]
24
23
  adviceMessage: string[]
25
24
 
26
- constructor(
27
- issueMessage: string[],
28
- issueMessageCves: string[],
29
- adviceMessage: string[]
30
- ) {
25
+ constructor(issueMessage: string[], adviceMessage: string[]) {
31
26
  this.issueMessage = issueMessage
32
- this.issueMessageCves = issueMessageCves
33
27
  this.adviceMessage = adviceMessage
34
28
  }
35
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 {
@@ -9,6 +9,8 @@ import {
9
9
  import i18n from 'i18n'
10
10
  import chalk from 'chalk'
11
11
  import * as constants from '../../../constants/constants'
12
+ import { SeverityCountModel } from './models/severityCountModel'
13
+ import * as common from '../../../common/fail'
12
14
 
13
15
  export function convertKeysToStandardFormat(config: any, guidance: any) {
14
16
  let convertedGuidance = guidance
@@ -72,6 +74,7 @@ export function formatVulnerabilityOutput(
72
74
  String(0)
73
75
  )
74
76
  )
77
+ return [false, 0, [new SeverityCountModel()]]
75
78
  } else {
76
79
  let numberOfCves = 0
77
80
  vulnerableLibraries.forEach(lib => (numberOfCves += lib.cveArray.length))
@@ -83,12 +86,13 @@ export function formatVulnerabilityOutput(
83
86
  numberOfCves,
84
87
  guidance
85
88
  )
86
-
87
- return [
88
- hasSomeVulnerabilitiesReported,
89
- numberOfCves,
90
- severityCountAllLibraries(vulnerableLibraries)
91
- ]
89
+ let severityCount = new SeverityCountModel()
90
+ severityCount = severityCountAllLibraries(
91
+ vulnerableLibraries,
92
+ severityCount
93
+ )
94
+ severityCount.total = severityCount.getTotal
95
+ return [hasSomeVulnerabilitiesReported, numberOfCves, severityCount]
92
96
  }
93
97
  }
94
98
 
@@ -97,8 +101,7 @@ export async function vulnerabilityReportV2(config: any, reportId: string) {
97
101
  const reportResponse = await getReport(config, reportId)
98
102
 
99
103
  if (reportResponse !== undefined) {
100
- const name = config.applicationName
101
- formatVulnerabilityOutput(
104
+ let output = formatVulnerabilityOutput(
102
105
  reportResponse.vulnerabilities,
103
106
  config.applicationId,
104
107
  config,
@@ -106,5 +109,9 @@ export async function vulnerabilityReportV2(config: any, reportId: string) {
106
109
  ? reportResponse.remediationGuidance
107
110
  : {}
108
111
  )
112
+
113
+ if (config.fail) {
114
+ common.processFail(config, output[2])
115
+ }
109
116
  }
110
117
  }
@@ -75,9 +75,9 @@ export function convertGenericToTypedLibraryVulns(libraries: any) {
75
75
  }
76
76
 
77
77
  export function severityCountAllLibraries(
78
- vulnerableLibraries: ReportLibraryModel[]
78
+ vulnerableLibraries: ReportLibraryModel[],
79
+ severityCount: SeverityCountModel
79
80
  ) {
80
- const severityCount = new SeverityCountModel()
81
81
  vulnerableLibraries.forEach(lib =>
82
82
  severityCountAllCVEs(lib.cveArray, severityCount)
83
83
  )
@@ -1,9 +1,16 @@
1
1
  import paramHandler from '../../utils/paramsUtil/paramHandler'
2
2
  import constants from '../../constants'
3
- import cliOptions from '../../utils/parsedCLIOptions'
3
+ import { getCommandLineArgsCustom } from '../../utils/parsedCLIOptions'
4
+ import { ContrastConf } from '../../utils/getConfig'
4
5
 
5
- export const getAuditConfig = (argv: string[]): { [key: string]: string } => {
6
- const auditParameters = cliOptions.getCommandLineArgsCustom(
6
+ export const getAuditConfig = async (
7
+ contrastConf: ContrastConf,
8
+ command: string,
9
+ argv: string[]
10
+ ): Promise<{ [key: string]: string }> => {
11
+ const auditParameters = await getCommandLineArgsCustom(
12
+ contrastConf,
13
+ command,
7
14
  argv,
8
15
  constants.commandLineDefinitions.auditOptionDefinitions
9
16
  )
@@ -1,16 +1,30 @@
1
1
  import { getAuditConfig } from './auditConfig'
2
2
  import { auditUsageGuide } from './help'
3
3
  import { processSca } from '../scan/sca/scaAnalysis'
4
+ import { sendTelemetryConfigAsObject } from '../../telemetry/telemetry'
5
+ import { ContrastConf } from '../../utils/getConfig'
4
6
 
5
7
  export type parameterInput = string[]
6
8
 
7
- export const processAudit = async (argv: parameterInput) => {
9
+ export const processAudit = async (
10
+ contrastConf: ContrastConf,
11
+ argv: parameterInput
12
+ ) => {
8
13
  if (argv.indexOf('--help') != -1) {
9
14
  printHelpMessage()
10
15
  process.exit(0)
11
16
  }
12
- const config = getAuditConfig(argv)
17
+
18
+ const config = await getAuditConfig(contrastConf, 'audit', argv)
13
19
  await processSca(config)
20
+ await sendTelemetryConfigAsObject(
21
+ config,
22
+ 'audit',
23
+ argv,
24
+ 'SUCCESS',
25
+ // @ts-ignore
26
+ config.language
27
+ )
14
28
  }
15
29
 
16
30
  const printHelpMessage = () => {
@@ -16,7 +16,9 @@ const constants = require('../../constants')
16
16
  const commandLineUsage = require('command-line-usage')
17
17
 
18
18
  const processAuth = async (argv, config) => {
19
- let authParams = parsedCLIOptions.getCommandLineArgsCustom(
19
+ let authParams = await parsedCLIOptions.getCommandLineArgsCustom(
20
+ config,
21
+ 'auth',
20
22
  argv,
21
23
  constants.commandLineDefinitions.authOptionDefinitions
22
24
  )
@@ -3,9 +3,11 @@ const constants = require('../../constants')
3
3
  const commandLineUsage = require('command-line-usage')
4
4
  const i18n = require('i18n')
5
5
 
6
- const processConfig = (argv, config) => {
6
+ const processConfig = async (argv, config) => {
7
7
  try {
8
- let configParams = parsedCLIOptions.getCommandLineArgsCustom(
8
+ let configParams = await parsedCLIOptions.getCommandLineArgsCustom(
9
+ config,
10
+ 'config',
9
11
  argv,
10
12
  constants.commandLineDefinitions.configOptionDefinitions
11
13
  )
@@ -4,23 +4,37 @@ const { saveScanFile } = require('../../utils/saveFile')
4
4
  const { ScanResultsModel } = require('../../scan/models/scanResultsModel')
5
5
  const { formatScanOutput } = require('../../scan/formatScanOutput')
6
6
  const { processSca } = require('./sca/scaAnalysis')
7
+ const common = require('../../common/fail')
8
+ const { sendTelemetryConfigAsObject } = require('../../telemetry/telemetry')
7
9
 
8
- const processScan = async argvMain => {
9
- let config = scanConfig.getScanConfig(argvMain)
10
+ const processScan = async (contrastConf, argv) => {
11
+ let config = await scanConfig.getScanConfig(contrastConf, 'scan', argv)
12
+ let output = undefined
10
13
  //try SCA analysis first
11
14
  if (config.experimental) {
12
- await processSca(config)
15
+ await processSca(config, argv)
13
16
  }
14
17
 
15
18
  let scanResults = new ScanResultsModel(await startScan(config))
19
+ await sendTelemetryConfigAsObject(
20
+ config,
21
+ 'scan',
22
+ argv,
23
+ 'SUCCESS',
24
+ scanResults.scanDetail.language
25
+ )
16
26
 
17
27
  if (scanResults.scanResultsInstances !== undefined) {
18
- formatScanOutput(scanResults)
28
+ output = formatScanOutput(scanResults)
19
29
  }
20
30
 
21
31
  if (config.save !== undefined) {
22
32
  await saveScanFile(config, scanResults)
23
33
  }
34
+
35
+ if (config.fail) {
36
+ common.processFail(config, output)
37
+ }
24
38
  }
25
39
 
26
40
  module.exports = {
@@ -24,16 +24,22 @@ const {
24
24
  } = require('../../../audit/languageAnalysisEngine/report/reportingFeature')
25
25
  const auditSave = require('../../../audit/save')
26
26
  const { dotNetAnalysis } = require('../../../scaAnalysis/dotnet')
27
+ const { auditUsageGuide } = require('../../audit/help')
27
28
  const rootFile = require('../../../audit/languageAnalysisEngine/getProjectRootFilenames')
28
29
  const path = require('path')
29
30
  const processSca = async config => {
30
31
  const startTime = performance.now()
31
32
  let filesFound
32
33
 
34
+ if (config.help) {
35
+ console.log(auditUsageGuide)
36
+ process.exit(0)
37
+ }
38
+
33
39
  const projectStats = await rootFile.getProjectStats(config.file)
34
40
  let pathWithFile = projectStats.isFile()
35
41
 
36
- let fileName = config.file
42
+ config.fileName = config.file
37
43
  config.file = pathWithFile
38
44
  ? rootFile.getDirectoryFromPathGiven(config.file).concat('/')
39
45
  : config.file
@@ -42,7 +48,7 @@ const processSca = async config => {
42
48
 
43
49
  if (filesFound.length > 1 && pathWithFile) {
44
50
  filesFound = filesFound.filter(i =>
45
- Object.values(i)[0].includes(path.basename(fileName))
51
+ Object.values(i)[0].includes(path.basename(config.fileName))
46
52
  )
47
53
  }
48
54
 
@@ -127,7 +133,9 @@ const processSca = async config => {
127
133
  throw new Error()
128
134
  } else {
129
135
  throw new Error(
130
- 'multiple language files detected, please use --file to specify a directory or the file where dependencies are declared'
136
+ `multiple language files detected \n` +
137
+ JSON.stringify(filesFound) +
138
+ `\nplease use --file to audit one language only. Example: contrast audit --file package-lock.json`
131
139
  )
132
140
  }
133
141
  }
@@ -346,6 +346,16 @@ HTTPClient.prototype.getLatestVersion = function getLatestVersion() {
346
346
  return requestUtils.sendRequest({ method: 'get', options })
347
347
  }
348
348
 
349
+ HTTPClient.prototype.postTelemetry = function postTelemetry(
350
+ config,
351
+ requestBody
352
+ ) {
353
+ const options = _.cloneDeep(this.requestOptions)
354
+ options.url = createTelemetryEventUrl(config)
355
+ options.body = requestBody
356
+ return requestUtils.sendRequest({ method: 'post', options })
357
+ }
358
+
349
359
  // analytics
350
360
 
351
361
  HTTPClient.prototype.postAnalyticsFunction = function (config, provider, body) {
@@ -439,6 +449,10 @@ function createSbomUrl(config, type) {
439
449
  return `${config.host}/Contrast/api/ng/${config.organizationId}/applications/${config.applicationId}/libraries/sbom/${type}`
440
450
  }
441
451
 
452
+ function createTelemetryEventUrl(config) {
453
+ return `${config.host}/Contrast/api/sast/organizations/${config.organizationId}/cli`
454
+ }
455
+
442
456
  module.exports = HTTPClient
443
457
  module.exports.pollForAuthUrl = pollForAuthUrl
444
458
  module.exports.getServerlessHost = getServerlessHost
@@ -0,0 +1,75 @@
1
+ const i18n = require('i18n')
2
+
3
+ const processFail = (config, reportResults) => {
4
+ if (config.severity !== undefined) {
5
+ if (
6
+ reportResults[config.severity] !== undefined &&
7
+ isSeverityViolation(config.severity, reportResults)
8
+ ) {
9
+ failPipeline('failSeverityOptionErrorMessage')
10
+ }
11
+ }
12
+
13
+ if (config.severity === undefined && reportResults.total > 0) {
14
+ failPipeline('failThresholdOptionErrorMessage')
15
+ }
16
+ }
17
+
18
+ const isSeverityViolation = (severity, reportResults) => {
19
+ let count = 0
20
+ switch (severity) {
21
+ case 'critical':
22
+ count += reportResults.critical
23
+ break
24
+ case 'high':
25
+ count += reportResults.high + reportResults.critical
26
+ break
27
+ case 'medium':
28
+ count += reportResults.medium + reportResults.low + reportResults.critical
29
+ break
30
+ case 'low':
31
+ count +=
32
+ reportResults.high + reportResults.critical + reportResults.medium
33
+ break
34
+ case 'note':
35
+ if (reportResults.note == reportResults.total) {
36
+ count = 0
37
+ } else {
38
+ count = reportResults.total
39
+ }
40
+ break
41
+ default:
42
+ count = 0
43
+ }
44
+ return count > 0
45
+ }
46
+
47
+ const failPipeline = (message = '') => {
48
+ console.log(
49
+ '\n ******************************** ' +
50
+ i18n.__('snapshotFailureHeader') +
51
+ ' *********************************\n' +
52
+ i18n.__(message)
53
+ )
54
+ process.exit(1)
55
+ }
56
+
57
+ const parseSeverity = severity => {
58
+ const severities = ['NOTE', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL']
59
+ if (severities.includes(severity.toUpperCase())) {
60
+ return severity.toLowerCase()
61
+ } else {
62
+ console.log(
63
+ severity +
64
+ ' Not recognised as a severity type please use LOW, MEDIUM, HIGH, CRITICAL, NOTE'
65
+ )
66
+ return undefined
67
+ }
68
+ }
69
+
70
+ module.exports = {
71
+ failPipeline,
72
+ processFail,
73
+ isSeverityViolation,
74
+ parseSeverity
75
+ }
@@ -20,7 +20,7 @@ const getLatestVersion = async (config: any) => {
20
20
 
21
21
  // @ts-ignore
22
22
  export async function findLatestCLIVersion(config: ContrastConf) {
23
- const messageHidden = config.get('updateMessageHidden') as boolean
23
+ const messageHidden = config.get('isCI') as boolean
24
24
 
25
25
  if (!messageHidden) {
26
26
  let latestCLIVersion: string = await getLatestVersion(config)
@@ -14,7 +14,7 @@ const HIGH = 'HIGH'
14
14
  const CRITICAL = 'CRITICAL'
15
15
  // App
16
16
  const APP_NAME = 'contrast'
17
- const APP_VERSION = '1.0.10'
17
+ const APP_VERSION = '1.0.11'
18
18
  const TIMEOUT = 120000
19
19
  const HIGH_COLOUR = '#ff9900'
20
20
  const CRITICAL_COLOUR = '#e35858'
@@ -121,9 +121,11 @@ const en_locales = () => {
121
121
  'The name of the application cataloged by Contrast UI',
122
122
  constantsCatalogueApplication:
123
123
  'Provide this if you want to catalogue an application',
124
+ failOptionErrorMessage:
125
+ ' FAIL - CVEs have been detected that match at least the cve_severity option specified.',
124
126
  constantsLanguage:
125
127
  'Valid values are JAVA, DOTNET, NODE, PYTHON and RUBY. If there are multiple project configuration files in the project_path, language is also required. Also, provide this when cataloguing an application',
126
- constantsFilePath: `Path of the file you want to perform an SCA audit on. If no folder is specified, Contrast searches for dependency files in the working directory.`,
128
+ constantsFilePath: `Specify a directory or the file where dependencies are declared. (By default, CodeSec will search for project files in the current directory.)`,
127
129
  constantsSilent: 'Silences JSON output.',
128
130
  constantsAppGroups:
129
131
  'Assign your application to one or more pre-existing groups when using the catalogue command. Group lists should be comma separated.',
@@ -142,8 +144,9 @@ const en_locales = () => {
142
144
  constantsReport: 'Display vulnerability information for this application',
143
145
  constantsFail:
144
146
  'Set the process to fail if this option is set in combination with --cve_severity.',
145
- failOptionErrorMessage:
146
- ' FAIL - CVEs have been detected that match at least the cve_severity or cve_threshold option specified.',
147
+ failThresholdOptionErrorMessage: 'More than 0 vulnerabilities found',
148
+ failSeverityOptionErrorMessage:
149
+ ' FAIL - Results detected vulnerabilities over accepted severity level',
147
150
  constantsSeverity:
148
151
  'Allows the user to report libraries with vulnerabilities above a chosen severity level. For example, cve_severity medium only reports libraries with vulnerabilities at medium or higher severity. Values for level are high, medium or low.',
149
152
  constantsCount: 'The number of CVEs that must be exceeded to fail a build',
@@ -414,7 +417,8 @@ const en_locales = () => {
414
417
  auditOptionsSaveDescription:
415
418
  'Generate and save an SBOM (Software Bill of Materials)\n',
416
419
  auditOptionsSaveOptionsDescription:
417
- 'Valid options are: spdx, cyclonedx (cycloneDX is the default format)',
420
+ 'Valid options are: --save spdx and --save cyclonedx (CycloneDX is the default format.)',
421
+ exceededFreeTier: `It looks like you are really loving CodeSec! \nYou have reached the monthly scan limit on the FREE tier. \nPlease contact sales@contrastsecurity.com to upgrade.`,
418
422
  scanNotCompleted:
419
423
  'Scan not completed. Check for framework and language support here: %s',
420
424
  auditNotCompleted: 'audit not completed. Please try again',