@contrast/contrast 1.0.13 → 1.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,14 +30,8 @@ export function findHighestSeverityCVE(cveArray: ReportCVEModel[]) {
30
30
  return orderBy(mappedToReportSeverityModels, cve => cve?.priority)[0]
31
31
  }
32
32
 
33
- export function findCVESeveritiesAndOrderByHighestPriority(
34
- cves: ReportCVEModel[]
35
- ) {
36
- return orderBy(
37
- cves.map(cve => findCVESeverity(cve)),
38
- ['priority'],
39
- ['asc']
40
- )
33
+ export function orderByHighestPriority(cves: ReportCVEModel[]) {
34
+ return orderBy(cves, ['priority'], ['asc'])
41
35
  }
42
36
 
43
37
  export function findCVESeverity(cve: ReportCVEModel) {
@@ -1,7 +1,6 @@
1
1
  const autoDetection = require('../../../scan/autoDetection')
2
2
  const javaAnalysis = require('../../../scaAnalysis/java')
3
3
  const treeUpload = require('../../../scaAnalysis/common/treeUpload')
4
- const scaUpload = require('../../../scaAnalysis/common/scaServicesUpload')
5
4
  const auditController = require('../../audit/auditController')
6
5
  const {
7
6
  supportedLanguages: { JAVA, GO, PYTHON, RUBY, JAVASCRIPT, NODE, PHP, DOTNET }
@@ -105,9 +104,9 @@ const processSca = async config => {
105
104
  }
106
105
 
107
106
  // if (config.experimental) {
108
- // await scaUpload.scaTreeUpload(messageToSend, config)
109
- // } else
110
- // {
107
+ // // const reports = await scaUpload.scaTreeUpload(messageToSend, config)
108
+ // auditReport.processAuditReport(config, 'reports')
109
+ // } else {
111
110
  console.log('') //empty log for space before spinner
112
111
  //send message to TS
113
112
  const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'))
@@ -38,8 +38,7 @@ const reportFailureError = () => {
38
38
  console.log(i18n.__('auditReportFailureMessage'))
39
39
  }
40
40
 
41
- const genericError = (missingCliOption: string) => {
42
- console.log(missingCliOption)
41
+ const genericError = () => {
43
42
  console.error(i18n.__('genericErrorMessage'))
44
43
  process.exit(1)
45
44
  }
@@ -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.13'
17
+ const APP_VERSION = '1.0.14'
18
18
  const TIMEOUT = 120000
19
19
  const HIGH_COLOUR = '#ff9900'
20
20
  const CRITICAL_COLOUR = '#e35858'
@@ -122,6 +122,8 @@ const en_locales = () => {
122
122
  'Provide this if you want to catalogue an application',
123
123
  failOptionErrorMessage:
124
124
  ' FAIL - CVEs have been detected that match at least the cve_severity option specified.',
125
+ failOptionMessage:
126
+ ' Use with contrast scan or contrast audit. Detects failures based on the severity level specified with the --severity command. For example, "contrast scan --fail --severity high". Returns all failures if no severity level is specified.',
125
127
  constantsLanguage:
126
128
  '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',
127
129
  constantsFilePath: `Specify a directory or the file where dependencies are declared. (By default, CodeSec will search for project files in the current directory.)`,
@@ -147,7 +149,7 @@ const en_locales = () => {
147
149
  failSeverityOptionErrorMessage:
148
150
  ' FAIL - Results detected vulnerabilities over accepted severity level',
149
151
  constantsSeverity:
150
- '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.',
152
+ 'Use with "contrast scan --fail --severity high" or "contrast audit --fail --severity high". Set the severity level to detect vulnerabilities or dependencies. Severity levels are critical, high, medium, low or note.',
151
153
  constantsCount: 'The number of CVEs that must be exceeded to fail a build',
152
154
  constantsHeader: 'CodeSec by Contrast Security',
153
155
  configHeader2: 'Config options',
@@ -170,7 +172,7 @@ const en_locales = () => {
170
172
  constantsConfigUsageContents: 'view / clear the configuration',
171
173
  constantsPrerequisitesContent:
172
174
  'To scan a Java project you will need a .jar or .war file for analysis\n' +
173
- 'To scan a Javascript project you will need a .js or.zip file for analysis\n' +
175
+ 'To scan a Javascript project you will need a single .js or a .zip of multiple .js files\n' +
174
176
  'To scan a .NET c# webforms project you will need a .exe or a .zip file for analysis\n',
175
177
  constantsUsage: 'Usage',
176
178
  constantsUsageCommandExample: 'contrast [command] [options]',
@@ -317,7 +319,17 @@ const en_locales = () => {
317
319
  scanOptionsVerboseSummary: ' Returns extended information to the terminal.',
318
320
  authSuccessMessage: 'Authentication successful',
319
321
  runAuthSuccessMessage:
320
- "Now you can use CodeSec by Contrast \nRun: \n'contrast scan' to run CodeSec’s industry leading SAST scanner \n'contrast audit' to find vulnerabilities in your open source dependencies \n'contrast lambda' to secure your AWS serverless functions\nor 'contrast help' to learn more about the capabilities.",
322
+ chalk.bold('CodeSec by Contrast') +
323
+ '\nScan, secure and ship your code in minutes for FREE. \n' +
324
+ chalk.bold('\nRun\n') +
325
+ chalk.bold('\ncontrast scan') +
326
+ " to run Contrast's industry leading SAST scanner. \nSupports Java, JavaScript and .Net \n" +
327
+ chalk.bold('\ncontrast audit') +
328
+ ' to find vulnerabilities in your open source dependencies.\nSupports Java, .NET, Node, Ruby, Python, Go and PHP \n' +
329
+ chalk.bold('\ncontrast lambda') +
330
+ ' to secure your AWS serverless functions. \nSupports Java and Python \n' +
331
+ chalk.bold('\ncontrast help') +
332
+ ' to learn more about the capabilities.',
321
333
  authWaitingMessage: 'Waiting for auth...',
322
334
  authTimedOutMessage: 'Auth Timed out, try again',
323
335
  zipErrorScan:
@@ -325,10 +337,7 @@ const en_locales = () => {
325
337
  unknownFileErrorScan: 'Unsupported file selected for Scan.',
326
338
  foundScanFile: 'Found: %s',
327
339
  foundDetailedVulnerabilities:
328
- chalk.bold('%s Critical') +
329
- ' | ' +
330
- chalk.bold('%s High') +
331
- ' | %s Medium | %s Low | %s Note',
340
+ chalk.bold('%s') + ' | ' + chalk.bold('%s') + ' | %s | %s | %s ',
332
341
  requiredParams: 'All required parameters are not present.',
333
342
  timeoutScan: 'Timeout set to 5 minutes.',
334
343
  searchingScanFileDirectory: 'Searching for file to scan from %s...',
package/src/constants.js CHANGED
@@ -115,7 +115,7 @@ const scanOptionDefinitions = [
115
115
  '{bold ' +
116
116
  i18n.__('constantsOptional') +
117
117
  '}: ' +
118
- i18n.__('failOptionErrorMessage')
118
+ i18n.__('failOptionMessage')
119
119
  },
120
120
  {
121
121
  name: 'severity',
@@ -247,7 +247,7 @@ const auditOptionDefinitions = [
247
247
  '{bold ' +
248
248
  i18n.__('constantsOptional') +
249
249
  '}: ' +
250
- i18n.__('failOptionErrorMessage')
250
+ i18n.__('failOptionMessage')
251
251
  },
252
252
  {
253
253
  name: 'severity',
package/src/index.ts CHANGED
@@ -95,9 +95,8 @@ const start = async () => {
95
95
  ? console.log(
96
96
  `Unknown Command: Did you mean "${foundCommand}"? \nUse "${foundCommand} --help" for the full list of options`
97
97
  )
98
- : console.log(
99
- `Unknown Command: ${command} \nUse --help for the full list`
100
- )
98
+ : console.log(`\nUnknown Command: ${command} \n`)
99
+ console.log(mainUsageGuide)
101
100
  await sendTelemetryConfigAsConfObj(
102
101
  config,
103
102
  command,
@@ -106,9 +105,8 @@ const start = async () => {
106
105
  'undefined'
107
106
  )
108
107
  } else {
109
- console.log(
110
- `Unknown Command: ${command} \nUse --help for the full list`
111
- )
108
+ console.log(`\nUnknown Command: ${command}\n`)
109
+ console.log(mainUsageGuide)
112
110
  await sendTelemetryConfigAsConfObj(
113
111
  config,
114
112
  command,
@@ -126,7 +126,7 @@ const processLambda = async (argv: string[]) => {
126
126
 
127
127
  const getAvailableFunctions = async (lambdaOptions: LambdaOptions) => {
128
128
  const lambdas = await getAllLambdas(lambdaOptions)
129
- printAvailableLambdas(lambdas, { runtimes: ['python', 'java'] })
129
+ printAvailableLambdas(lambdas, { runtimes: ['python', 'java', 'node'] })
130
130
  }
131
131
 
132
132
  const actualProcessLambda = async (lambdaOptions: LambdaOptions) => {
@@ -11,7 +11,7 @@ import ora from '../utils/oraWrapper'
11
11
  import { LambdaOptions } from './lambda'
12
12
  import { log, getReadableFileSize } from './logUtils'
13
13
 
14
- type RuntimeLanguage = 'java' | 'python'
14
+ type RuntimeLanguage = 'java' | 'python' | 'node'
15
15
 
16
16
  type FilterLambdas = {
17
17
  runtimes: RuntimeLanguage[]
@@ -0,0 +1,108 @@
1
+ const {
2
+ getSeverityCounts,
3
+ createSummaryMessageTop,
4
+ printVulnInfo,
5
+ getReportTable,
6
+ getIssueRow,
7
+ printNoVulnFoundMsg
8
+ } = require('../../audit/report/commonReportingFunctions')
9
+ const { orderBy } = require('lodash')
10
+ const { assignBySeverity } = require('../../scan/formatScanOutput')
11
+ const chalk = require('chalk')
12
+ const { CE_URL } = require('../../constants/constants')
13
+ const common = require('../../common/fail')
14
+
15
+ const processAuditReport = (config, results) => {
16
+ let severityCounts = {}
17
+ if (results !== undefined) {
18
+ severityCounts = formatScaServicesReport(config, results)
19
+ }
20
+
21
+ if (config.fail) {
22
+ common.processFail(config, severityCounts)
23
+ }
24
+ }
25
+ const formatScaServicesReport = (config, results) => {
26
+ const projectOverviewCount = getSeverityCounts(results)
27
+
28
+ if (projectOverviewCount.total === 0) {
29
+ printNoVulnFoundMsg()
30
+ return projectOverviewCount
31
+ } else {
32
+ let total = 0
33
+ const numberOfCves = results.length
34
+ const table = getReportTable()
35
+ let contrastHeaderNumCounter = 0
36
+ let assignPriorityToResults = results.map(result =>
37
+ assignBySeverity(result, result)
38
+ )
39
+ const numberOfVulns = results
40
+ .map(result => result.vulnerabilities)
41
+ .reduce((a, b) => {
42
+ return (total += b.length)
43
+ }, 0)
44
+ const outputOrderedByLowestSeverityAndLowestNumOfCvesFirst = orderBy(
45
+ assignPriorityToResults,
46
+ [
47
+ reportListItem => {
48
+ return reportListItem.priority
49
+ },
50
+ reportListItem => {
51
+ return reportListItem.vulnerabilities.length
52
+ }
53
+ ],
54
+ ['asc', 'desc']
55
+ )
56
+
57
+ for (const result of outputOrderedByLowestSeverityAndLowestNumOfCvesFirst) {
58
+ contrastHeaderNumCounter++
59
+ const cvesNum = result.vulnerabilities.length
60
+ const grammaticallyCorrectVul =
61
+ result.vulnerabilities.length > 1 ? 'vulnerabilities' : 'vulnerability'
62
+
63
+ const headerColour = chalk.hex(result.colour)
64
+ const headerRow = [
65
+ headerColour(
66
+ `CONTRAST-${contrastHeaderNumCounter.toString().padStart(3, '0')}`
67
+ ),
68
+ headerColour(`-`),
69
+ headerColour(`[${result.severity}] `) +
70
+ headerColour.bold(`${result.artifactName}`) +
71
+ ` introduces ${cvesNum} ${grammaticallyCorrectVul}`
72
+ ]
73
+
74
+ const adviceRow = [
75
+ chalk.bold(`Advice`),
76
+ chalk.bold(`:`),
77
+ `Change to version ${result.remediationAdvice.latestStableVersion}`
78
+ ]
79
+
80
+ let assignPriorityToVulns = result.vulnerabilities.map(result =>
81
+ assignBySeverity(result, result)
82
+ )
83
+ const issueRow = getIssueRow(assignPriorityToVulns)
84
+
85
+ table.push(headerRow, issueRow, adviceRow)
86
+ console.log()
87
+ }
88
+
89
+ console.log()
90
+ createSummaryMessageTop(numberOfCves, numberOfVulns)
91
+ console.log(table.toString() + '\n')
92
+ printVulnInfo(projectOverviewCount)
93
+
94
+ if (config.host !== CE_URL) {
95
+ console.log(
96
+ '\n' + chalk.bold('View your full dependency tree in Contrast:')
97
+ )
98
+ console.log(
99
+ `${config.host}/Contrast/static/ng/index.html#/${config.organizationId}/applications/${config.applicationId}/libs/dependency-tree`
100
+ )
101
+ }
102
+ return projectOverviewCount
103
+ }
104
+ }
105
+ module.exports = {
106
+ formatScaServicesReport,
107
+ processAuditReport
108
+ }
@@ -7,7 +7,7 @@ const scaTreeUpload = async (analysis, config) => {
7
7
  applicationId: config.applicationId,
8
8
  dependencyTree: analysis,
9
9
  organizationId: config.organizationId,
10
- language: 'NODE',
10
+ language: config.language,
11
11
  tool: {
12
12
  name: 'Contrast Codesec',
13
13
  version: APP_VERSION
@@ -27,26 +27,28 @@ const scaTreeUpload = async (analysis, config) => {
27
27
  .catch(err => {
28
28
  throw err
29
29
  })
30
+ console.log(' polling report')
30
31
 
31
32
  let keepChecking = true
33
+ let res
32
34
  while (keepChecking) {
33
- keepChecking = await client
34
- .scaServiceReportStatus(config, reportID)
35
- .then(res => {
36
- console.log(res.body)
37
- if (res.body.status == 'COMPLETED') {
38
- client.scaServiceReport(config, reportID).then(res => {
39
- console.log(res.statusCode)
40
- console.log(res.body)
41
- })
35
+ res = await client.scaServiceReportStatus(config, reportID).then(res => {
36
+ console.log(res.statusCode)
37
+ console.log(res.body)
38
+ if (res.body.status == 'COMPLETED') {
39
+ keepChecking = false
40
+ return client.scaServiceReport(config, reportID).then(res => {
41
+ return res.body
42
+ })
43
+ }
44
+ })
42
45
 
43
- return (keepChecking = false)
44
- } else {
45
- return (keepChecking = true)
46
- }
47
- })
46
+ if (!keepChecking) {
47
+ return res
48
+ }
48
49
  await requestUtils.sleep(5000)
49
50
  }
51
+ return res
50
52
  }
51
53
 
52
54
  module.exports = {
@@ -15,11 +15,15 @@ import {
15
15
  MEDIUM_COLOUR,
16
16
  NOTE_COLOUR
17
17
  } from '../constants/constants'
18
+ import {
19
+ getSeverityCounts,
20
+ printVulnInfo
21
+ } from '../audit/report/commonReportingFunctions'
18
22
 
19
23
  export function formatScanOutput(scanResults: ScanResultsModel) {
20
24
  const { scanResultsInstances } = scanResults
21
25
 
22
- const projectOverview = getProjectOverview(scanResultsInstances)
26
+ const projectOverview = getSeverityCounts(scanResultsInstances.content)
23
27
  if (scanResultsInstances.content.length === 0) {
24
28
  console.log(i18n.__('scanNoVulnerabilitiesFound'))
25
29
  console.log(i18n.__('scanNoVulnerabilitiesFoundSecureCode'))
@@ -108,47 +112,6 @@ export function formatScanOutput(scanResults: ScanResultsModel) {
108
112
  return projectOverview
109
113
  }
110
114
 
111
- function printVulnInfo(projectOverview: any) {
112
- const totalVulnerabilities = projectOverview.total
113
-
114
- const vulMessage =
115
- totalVulnerabilities === 1 ? `vulnerability` : `vulnerabilities`
116
- console.log(chalk.bold(`Found ${totalVulnerabilities} ${vulMessage}`))
117
- console.log(
118
- i18n.__(
119
- 'foundDetailedVulnerabilities',
120
- String(projectOverview.critical),
121
- String(projectOverview.high),
122
- String(projectOverview.medium),
123
- String(projectOverview.low),
124
- String(projectOverview.note)
125
- )
126
- )
127
- }
128
-
129
- export function getProjectOverview(scanResultsInstances: ScanResultsInstances) {
130
- const acc: any = {
131
- critical: 0,
132
- high: 0,
133
- medium: 0,
134
- low: 0,
135
- note: 0,
136
- total: 0
137
- }
138
- if (
139
- scanResultsInstances?.content &&
140
- scanResultsInstances.content.length > 0
141
- ) {
142
- scanResultsInstances.content.forEach((i: ResultContent) => {
143
- acc[i.severity.toLowerCase()] += 1
144
- acc.total += 1
145
- return acc
146
- })
147
- }
148
-
149
- return acc
150
- }
151
-
152
115
  export function formatLinks(objName: string, entry: any[]) {
153
116
  const line = chalk.bold(objName + ' : ')
154
117
  if (entry.length === 1) {