@contrast/contrast 1.0.4 → 1.0.7

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 (115) hide show
  1. package/.prettierignore +0 -3
  2. package/dist/audit/autodetection/autoDetectLanguage.js +32 -0
  3. package/dist/audit/catalogueApplication/catalogueApplication.js +2 -11
  4. package/dist/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +4 -2
  5. package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
  6. package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
  7. package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
  8. package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +6 -2
  9. package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +39 -1
  10. package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +69 -30
  11. package/dist/audit/languageAnalysisEngine/report/models/reportOutputModel.js +24 -0
  12. package/dist/audit/languageAnalysisEngine/report/models/reportSeverityModel.js +3 -1
  13. package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +13 -0
  14. package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +2 -2
  15. package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +56 -45
  16. package/dist/audit/languageAnalysisEngine/sendSnapshot.js +65 -17
  17. package/dist/commands/audit/auditConfig.js +8 -2
  18. package/dist/commands/audit/auditController.js +9 -3
  19. package/dist/commands/audit/processAudit.js +1 -1
  20. package/dist/commands/scan/processScan.js +7 -4
  21. package/dist/commands/scan/sca/scaAnalysis.js +60 -0
  22. package/dist/common/HTTPClient.js +50 -16
  23. package/dist/common/errorHandling.js +11 -16
  24. package/dist/common/versionChecker.js +1 -1
  25. package/dist/constants/constants.js +24 -2
  26. package/dist/constants/locales.js +31 -36
  27. package/dist/constants.js +20 -0
  28. package/dist/lambda/analytics.js +11 -0
  29. package/dist/lambda/lambda.js +35 -4
  30. package/dist/lambda/types.js +13 -0
  31. package/dist/scaAnalysis/common/formatMessage.js +35 -0
  32. package/dist/scaAnalysis/common/treeUpload.js +29 -0
  33. package/dist/scaAnalysis/go/goAnalysis.js +17 -0
  34. package/dist/scaAnalysis/go/goParseDeps.js +158 -0
  35. package/dist/scaAnalysis/go/goReadDepFile.js +23 -0
  36. package/dist/scaAnalysis/java/analysis.js +105 -0
  37. package/dist/scaAnalysis/java/index.js +18 -0
  38. package/dist/scaAnalysis/java/javaBuildDepsParser.js +339 -0
  39. package/dist/scaAnalysis/python/analysis.js +41 -0
  40. package/dist/scaAnalysis/python/index.js +10 -0
  41. package/dist/scaAnalysis/ruby/analysis.js +226 -0
  42. package/dist/scaAnalysis/ruby/index.js +10 -0
  43. package/dist/scan/autoDetection.js +50 -1
  44. package/dist/scan/fileUtils.js +80 -1
  45. package/dist/scan/formatScanOutput.js +213 -0
  46. package/dist/scan/help.js +3 -1
  47. package/dist/scan/models/groupedResultsModel.js +2 -1
  48. package/dist/scan/models/scanResultsModel.js +3 -1
  49. package/dist/scan/populateProjectIdAndProjectName.js +2 -1
  50. package/dist/scan/scan.js +6 -99
  51. package/dist/scan/scanConfig.js +6 -1
  52. package/dist/scan/scanController.js +26 -7
  53. package/dist/scan/scanResults.js +20 -20
  54. package/dist/utils/commonApi.js +4 -1
  55. package/dist/utils/oraWrapper.js +5 -1
  56. package/package.json +12 -7
  57. package/src/audit/autodetection/autoDetectLanguage.ts +40 -0
  58. package/src/audit/catalogueApplication/catalogueApplication.js +3 -16
  59. package/src/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +11 -8
  60. package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
  61. package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
  62. package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
  63. package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +17 -5
  64. package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +76 -3
  65. package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +122 -40
  66. package/src/audit/languageAnalysisEngine/report/models/reportLibraryModel.ts +3 -3
  67. package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +15 -11
  68. package/src/audit/languageAnalysisEngine/report/models/reportOutputModel.ts +29 -0
  69. package/src/audit/languageAnalysisEngine/report/models/reportSeverityModel.ts +12 -3
  70. package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +16 -0
  71. package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +3 -3
  72. package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +87 -65
  73. package/src/audit/languageAnalysisEngine/sendSnapshot.js +78 -25
  74. package/src/commands/audit/auditConfig.ts +12 -3
  75. package/src/commands/audit/auditController.ts +9 -3
  76. package/src/commands/audit/processAudit.ts +4 -1
  77. package/src/commands/scan/processScan.js +10 -4
  78. package/src/commands/scan/sca/scaAnalysis.js +83 -0
  79. package/src/common/HTTPClient.js +65 -25
  80. package/src/common/errorHandling.ts +14 -22
  81. package/src/common/versionChecker.ts +1 -1
  82. package/src/constants/constants.js +24 -2
  83. package/src/constants/locales.js +33 -50
  84. package/src/constants.js +22 -0
  85. package/src/lambda/analytics.ts +9 -0
  86. package/src/lambda/arn.ts +2 -1
  87. package/src/lambda/lambda.ts +37 -17
  88. package/src/lambda/types.ts +35 -0
  89. package/src/lambda/utils.ts +2 -7
  90. package/src/scaAnalysis/common/formatMessage.js +38 -0
  91. package/src/scaAnalysis/common/treeUpload.js +30 -0
  92. package/src/scaAnalysis/go/goAnalysis.js +19 -0
  93. package/src/scaAnalysis/go/goParseDeps.js +203 -0
  94. package/src/scaAnalysis/go/goReadDepFile.js +32 -0
  95. package/src/scaAnalysis/java/analysis.js +142 -0
  96. package/src/scaAnalysis/java/index.js +21 -0
  97. package/src/scaAnalysis/java/javaBuildDepsParser.js +404 -0
  98. package/src/scaAnalysis/python/analysis.js +48 -0
  99. package/src/scaAnalysis/python/index.js +11 -0
  100. package/src/scaAnalysis/ruby/analysis.js +282 -0
  101. package/src/scaAnalysis/ruby/index.js +11 -0
  102. package/src/scan/autoDetection.js +58 -1
  103. package/src/scan/fileUtils.js +99 -1
  104. package/src/scan/formatScanOutput.ts +249 -0
  105. package/src/scan/help.js +3 -1
  106. package/src/scan/models/groupedResultsModel.ts +7 -5
  107. package/src/scan/models/resultContentModel.ts +2 -2
  108. package/src/scan/models/scanResultsModel.ts +5 -2
  109. package/src/scan/populateProjectIdAndProjectName.js +3 -1
  110. package/src/scan/scan.ts +8 -136
  111. package/src/scan/scanConfig.js +5 -1
  112. package/src/scan/scanController.js +30 -10
  113. package/src/scan/scanResults.js +31 -18
  114. package/src/utils/commonApi.js +4 -1
  115. package/src/utils/oraWrapper.js +6 -1
@@ -0,0 +1,249 @@
1
+ import {
2
+ ScanResultsInstances,
3
+ ScanResultsModel
4
+ } from './models/scanResultsModel'
5
+ import i18n from 'i18n'
6
+ import chalk from 'chalk'
7
+ import { ResultContent } from './models/resultContentModel'
8
+ import { GroupedResultsModel } from './models/groupedResultsModel'
9
+ import { sortBy } from 'lodash'
10
+ import Table from 'cli-table3'
11
+ import {
12
+ CRITICAL_COLOUR,
13
+ HIGH_COLOUR,
14
+ LOW_COLOUR,
15
+ MEDIUM_COLOUR,
16
+ NOTE_COLOUR
17
+ } from '../constants/constants'
18
+
19
+ export function formatScanOutput(scanResults: ScanResultsModel) {
20
+ const { scanResultsInstances } = scanResults
21
+
22
+ const projectOverview = getProjectOverview(scanResultsInstances)
23
+ if (scanResultsInstances.content.length === 0) {
24
+ console.log(i18n.__('scanNoVulnerabilitiesFound'))
25
+ console.log(i18n.__('scanNoVulnerabilitiesFoundSecureCode'))
26
+ console.log(i18n.__('scanNoVulnerabilitiesFoundGoodWork'))
27
+ } else {
28
+ const message =
29
+ projectOverview.critical || projectOverview.high
30
+ ? 'Here are your top priorities to fix'
31
+ : "No major issues, here's what we found"
32
+ console.log(chalk.bold(message))
33
+ console.log()
34
+
35
+ let defaultView = getDefaultView(scanResultsInstances.content)
36
+
37
+ let count = defaultView.length
38
+ defaultView.forEach(entry => {
39
+ let table = new Table({
40
+ chars: {
41
+ top: '',
42
+ 'top-mid': '',
43
+ 'top-left': '',
44
+ 'top-right': '',
45
+ bottom: '',
46
+ 'bottom-mid': '',
47
+ 'bottom-left': '',
48
+ 'bottom-right': '',
49
+ left: '',
50
+ 'left-mid': '',
51
+ mid: '',
52
+ 'mid-mid': '',
53
+ right: '',
54
+ 'right-mid': '',
55
+ middle: ' '
56
+ },
57
+ style: { 'padding-left': 0, 'padding-right': 0 },
58
+ colAligns: ['right'],
59
+ wordWrap: true,
60
+ colWidths: [12, 1, 100]
61
+ })
62
+ let learnRow: string[] = []
63
+ let adviceRow = []
64
+ const headerRow = [
65
+ chalk
66
+ .hex(entry.colour)
67
+ .bold(`CONTRAST-${count.toString().padStart(3, '0')}`),
68
+ chalk.hex(entry.colour).bold('-'),
69
+ chalk.hex(entry.colour).bold(`[${entry.severity}] ${entry.ruleId}`) +
70
+ entry.message
71
+ ]
72
+
73
+ const codePath = entry.codePath?.replace(/^@/, '')
74
+
75
+ const codeRow = [
76
+ chalk.hex('#F6F5F5').bold(`Code`),
77
+ chalk.hex('#F6F5F5').bold(`:`),
78
+ chalk.hex('#F6F5F5').bold(`${codePath}`)
79
+ ]
80
+ const issueRow = [chalk.bold(`Issue`), chalk.bold(`:`), `${entry.issue}`]
81
+
82
+ table.push(headerRow, codeRow, issueRow)
83
+
84
+ if (entry?.advice) {
85
+ adviceRow = [
86
+ chalk.bold('Advice'),
87
+ chalk.bold(`:`),
88
+ stripTags(entry.advice)
89
+ ]
90
+ table.push(adviceRow)
91
+ }
92
+
93
+ if (entry?.learn && entry?.learn.length > 0) {
94
+ learnRow = [
95
+ chalk.bold('Learn'),
96
+ chalk.bold(`:`),
97
+ chalk.hex('#97f7f7').bold.underline(entry.learn[0])
98
+ ]
99
+ table.push(learnRow)
100
+ }
101
+ count--
102
+ console.log(table.toString())
103
+ console.log()
104
+ })
105
+ }
106
+ printVulnInfo(projectOverview)
107
+ }
108
+
109
+ function printVulnInfo(projectOverview: any) {
110
+ const totalVulnerabilities = projectOverview.total
111
+
112
+ const vulMessage =
113
+ totalVulnerabilities === 1 ? `vulnerability` : `vulnerabilities`
114
+ console.log(chalk.bold(`Found ${totalVulnerabilities} ${vulMessage}`))
115
+ console.log(
116
+ i18n.__(
117
+ 'foundDetailedVulnerabilities',
118
+ String(projectOverview.critical),
119
+ String(projectOverview.high),
120
+ String(projectOverview.medium),
121
+ String(projectOverview.low),
122
+ String(projectOverview.note)
123
+ )
124
+ )
125
+ }
126
+
127
+ export function getProjectOverview(scanResultsInstances: ScanResultsInstances) {
128
+ const acc: any = {
129
+ critical: 0,
130
+ high: 0,
131
+ medium: 0,
132
+ low: 0,
133
+ note: 0,
134
+ total: 0
135
+ }
136
+ if (
137
+ scanResultsInstances?.content &&
138
+ scanResultsInstances.content.length > 0
139
+ ) {
140
+ scanResultsInstances.content.forEach((i: ResultContent) => {
141
+ acc[i.severity.toLowerCase()] += 1
142
+ acc.total += 1
143
+ return acc
144
+ })
145
+ }
146
+
147
+ return acc
148
+ }
149
+
150
+ export function formatLinks(objName: string, entry: any[]) {
151
+ const line = chalk.bold(objName + ' : ')
152
+ if (entry.length === 1) {
153
+ console.log(line + chalk.hex('#97DCF7').bold.underline(entry[0]))
154
+ } else {
155
+ console.log(line)
156
+ entry.forEach(link => {
157
+ console.log(chalk.hex('#97DCF7').bold.underline(link))
158
+ })
159
+ }
160
+ }
161
+
162
+ export function getDefaultView(content: ResultContent[]) {
163
+ const groupTypeResults = [] as GroupedResultsModel[]
164
+
165
+ content.forEach(resultEntry => {
166
+ const groupResultsObj = new GroupedResultsModel(resultEntry.ruleId)
167
+ groupResultsObj.severity = resultEntry.severity
168
+ groupResultsObj.ruleId = resultEntry.ruleId
169
+ groupResultsObj.issue = stripTags(resultEntry.issue)
170
+ groupResultsObj.advice = resultEntry.advice
171
+ groupResultsObj.learn = resultEntry.learn
172
+ groupResultsObj.message = resultEntry.message?.text
173
+ ? editVulName(resultEntry.message.text) +
174
+ ':' +
175
+ getSourceLineNumber(resultEntry)
176
+ : ''
177
+ groupResultsObj.codePath = getLocationsSyncInfo(resultEntry)
178
+ groupTypeResults.push(groupResultsObj)
179
+ assignBySeverity(resultEntry, groupResultsObj)
180
+ })
181
+
182
+ return sortBy(groupTypeResults, ['priority']).reverse()
183
+ }
184
+ export function editVulName(message: string) {
185
+ return message.substring(message.indexOf(' in '))
186
+ }
187
+ export function getLocationsSyncInfo(resultEntry: ResultContent) {
188
+ const locationsMessage =
189
+ resultEntry.locations[0]?.physicalLocation?.artifactLocation?.uri || ''
190
+ const locationsLineNumber =
191
+ resultEntry.locations[0]?.physicalLocation?.region?.startLine || ''
192
+
193
+ if (!locationsLineNumber) {
194
+ return '@' + locationsMessage
195
+ }
196
+
197
+ return '@' + locationsMessage + ':' + locationsLineNumber
198
+ }
199
+
200
+ export function getSourceLineNumber(resultEntry: ResultContent) {
201
+ const locationsLineNumber =
202
+ resultEntry.locations[0]?.physicalLocation?.region?.startLine || ''
203
+ let codeFlowLineNumber = getCodeFlowInfo(resultEntry)
204
+
205
+ return codeFlowLineNumber ? codeFlowLineNumber : locationsLineNumber
206
+ }
207
+
208
+ export function getCodeFlowInfo(resultEntry: ResultContent) {
209
+ let result: any
210
+ resultEntry.codeFlows[0]?.threadFlows.forEach((i: { locations: any[] }) => {
211
+ return (result = i.locations.find(
212
+ (locations: { importance: string }) =>
213
+ locations.importance === 'essential'
214
+ ))
215
+ })
216
+
217
+ return result?.location?.physicalLocation?.region?.startLine
218
+ }
219
+
220
+ export function stripTags(oldString: string) {
221
+ return oldString.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim()
222
+ }
223
+
224
+ export function assignBySeverity(
225
+ entry: ResultContent,
226
+ assignedObj: GroupedResultsModel
227
+ ) {
228
+ if (entry.severity.toUpperCase() === 'CRITICAL') {
229
+ assignedObj.priority = 1
230
+ assignedObj.colour = CRITICAL_COLOUR
231
+ return assignedObj
232
+ } else if (entry.severity.toUpperCase() === 'HIGH') {
233
+ assignedObj.priority = 2
234
+ assignedObj.colour = HIGH_COLOUR
235
+ return assignedObj
236
+ } else if (entry.severity.toUpperCase() === 'MEDIUM') {
237
+ assignedObj.priority = 3
238
+ assignedObj.colour = MEDIUM_COLOUR
239
+ return assignedObj
240
+ } else if (entry.severity.toUpperCase() === 'LOW') {
241
+ assignedObj.priority = 4
242
+ assignedObj.colour = LOW_COLOUR
243
+ return assignedObj
244
+ } else if (entry.severity.toUpperCase() === 'NOTE') {
245
+ assignedObj.priority = 5
246
+ assignedObj.colour = NOTE_COLOUR
247
+ return assignedObj
248
+ }
249
+ }
package/src/scan/help.js CHANGED
@@ -30,7 +30,9 @@ const scanUsageGuide = commandLineUsage([
30
30
  'ff',
31
31
  'ignore-cert-errors',
32
32
  'verbose',
33
- 'debug'
33
+ 'debug',
34
+ 'experimental',
35
+ 'application-name'
34
36
  ]
35
37
  },
36
38
  {
@@ -1,18 +1,20 @@
1
1
  export class GroupedResultsModel {
2
2
  ruleId: string
3
- lineInfoSet: Set<string>
3
+ codePathSet: Set<string>
4
4
  cwe?: string[]
5
- owasp?: string[]
6
5
  reference?: string[]
7
- recommendation?: string
8
6
  severity?: string
9
7
  advice?: string
10
8
  learn?: string[]
11
9
  issue?: string
12
- message?: string
10
+ priority?: number
11
+ message?: string | undefined
12
+ colour: string
13
+ codePath?: string
13
14
 
14
15
  constructor(ruleId: string) {
15
16
  this.ruleId = ruleId
16
- this.lineInfoSet = new Set<string>
17
+ this.colour = '#999999'
18
+ this.codePathSet = new Set<string>()
17
19
  }
18
20
  }
@@ -5,7 +5,7 @@ interface ArtifactLocation {
5
5
  }
6
6
 
7
7
  interface Region {
8
- startLine: number
8
+ startLine: string
9
9
  snippet: Snippet
10
10
  }
11
11
 
@@ -52,7 +52,7 @@ export interface CodeFlow {
52
52
  }
53
53
 
54
54
  export interface ResultContent {
55
- message: {text: string};
55
+ message?: { text: string }
56
56
  id: string
57
57
  organizationId: string
58
58
  projectId: string
@@ -4,11 +4,14 @@ export class ScanResultsModel {
4
4
  projectOverview: ProjectOverview
5
5
  scanDetail: ScanDetail
6
6
  scanResultsInstances: ScanResultsInstances
7
+ newProject: boolean
7
8
 
8
9
  constructor(scan: any) {
9
10
  this.projectOverview = scan.projectOverview as ProjectOverview
10
11
  this.scanDetail = scan.scanDetail as ScanDetail
11
- this.scanResultsInstances = scan.scanResultsInstances as ScanResultsInstances
12
+ this.scanResultsInstances =
13
+ scan.scanResultsInstances as ScanResultsInstances
14
+ this.newProject = scan.newProject
12
15
  }
13
16
  }
14
17
 
@@ -49,4 +52,4 @@ export interface ScanDetail {
49
52
 
50
53
  export interface ScanResultsInstances {
51
54
  content: ResultContent[]
52
- }
55
+ }
@@ -8,9 +8,11 @@ const populateProjectId = async config => {
8
8
  proj = await getExistingProjectIdByName(config, client).then(res => {
9
9
  return res
10
10
  })
11
+
12
+ return { projectId: proj, isNewProject: false }
11
13
  }
12
14
 
13
- return proj
15
+ return { projectId: proj, isNewProject: true }
14
16
  }
15
17
 
16
18
  const createProjectId = async (config, client) => {
package/src/scan/scan.ts CHANGED
@@ -2,10 +2,6 @@ import commonApi from '../utils/commonApi.js'
2
2
  import fileUtils from '../scan/fileUtils'
3
3
  import i18n from 'i18n'
4
4
  import oraWrapper from '../utils/oraWrapper'
5
- import chalk from 'chalk'
6
- import { ProjectOverview, ScanResultsModel } from './models/scanResultsModel'
7
- import { Location, ResultContent } from './models/resultContentModel'
8
- import { GroupedResultsModel } from './models/groupedResultsModel'
9
5
 
10
6
  export const allowedFileTypes = ['.jar', '.war', '.js', '.zip', '.exe']
11
7
 
@@ -44,149 +40,25 @@ export const sendScan = async (config: any) => {
44
40
  return res.body.id
45
41
  } else {
46
42
  if (config.debug) {
47
- console.log(res.statusCode)
48
43
  console.log(config)
44
+ oraWrapper.failSpinner(
45
+ startUploadSpinner,
46
+ i18n.__('uploadingScanFail')
47
+ )
48
+ console.log(i18n.__('genericServiceError', res.statusCode))
49
49
  }
50
- oraWrapper.failSpinner(
51
- startUploadSpinner,
52
- i18n.__('uploadingScanFail')
53
- )
54
50
  if (res.statusCode === 403) {
55
51
  console.log(i18n.__('permissionsError'))
56
52
  process.exit(1)
57
53
  }
58
- console.log(i18n.__('genericServiceError', res.statusCode))
54
+ oraWrapper.stopSpinner(startUploadSpinner)
55
+ console.log('Contrast Scan Finished')
59
56
  process.exit(1)
60
57
  }
61
58
  })
62
59
  .catch(err => {
60
+ oraWrapper.stopSpinner(startUploadSpinner)
63
61
  console.log(err)
64
62
  })
65
63
  }
66
64
  }
67
-
68
- export function formatScanOutput(scanResults: ScanResultsModel) {
69
- const { projectOverview, scanResultsInstances } = scanResults
70
-
71
- if (scanResultsInstances.content.length === 0) {
72
- console.log(i18n.__('scanNoVulnerabilitiesFound'))
73
- } else {
74
- const message =
75
- projectOverview.critical || projectOverview.high
76
- ? 'Here are your top priorities to fix'
77
- : "No major issues, here's what we found"
78
- console.log(chalk.bold(message))
79
- console.log()
80
-
81
- const groups = getGroups(scanResultsInstances.content)
82
-
83
- groups.forEach(entry => {
84
- console.log(
85
- chalk.bold(
86
- `[ ${entry.severity} ] | ${entry.ruleId} (${entry.lineInfoSet.size}) - ` +
87
- `${entry.message}`
88
- )
89
- )
90
-
91
- let count = 1
92
- entry.lineInfoSet.forEach(lineInfo => {
93
- console.log(`\t ${count}. ${lineInfo}`)
94
- count++
95
- })
96
-
97
- if (entry?.issue) {
98
- console.log(chalk.bold('Issue' + ': ') + entry.issue)
99
- }
100
-
101
- if (entry?.advice) {
102
- console.log(chalk.bold('Advice' + ': ') + entry.advice)
103
- }
104
-
105
- if (entry?.learn && entry?.learn.length > 0) {
106
- formatLinks('Learn', entry.learn)
107
- }
108
- console.log()
109
- })
110
-
111
- printVulnInfo(projectOverview)
112
- }
113
- }
114
-
115
- function printVulnInfo(projectOverview: ProjectOverview) {
116
- const totalVulnerabilities = getTotalVulns(projectOverview)
117
-
118
- const vulMessage =
119
- totalVulnerabilities === 1 ? `vulnerability` : `vulnerabilities`
120
- console.log(chalk.bold(`Found ${totalVulnerabilities} ${vulMessage}`))
121
- console.log(
122
- i18n.__(
123
- 'foundDetailedVulnerabilities',
124
- String(projectOverview.critical),
125
- String(projectOverview.high),
126
- String(projectOverview.medium),
127
- String(projectOverview.low),
128
- String(projectOverview.note)
129
- )
130
- )
131
- }
132
-
133
- function getTotalVulns(projectOverview: ProjectOverview) {
134
- return (
135
- projectOverview.critical +
136
- projectOverview.high +
137
- projectOverview.medium +
138
- projectOverview.low +
139
- projectOverview.note
140
- )
141
- }
142
-
143
- export function formatLinks(objName: string, entry: any[]) {
144
- console.log(chalk.bold(objName + ':'))
145
- entry.forEach(link => {
146
- console.log(link)
147
- })
148
- }
149
-
150
- export function getGroups(content: ResultContent[]) {
151
- const groupTypeSet = new Set(content.map(({ ruleId }) => ruleId))
152
- const groupTypeResults = [] as GroupedResultsModel[]
153
-
154
- groupTypeSet.forEach(groupName => {
155
- const groupResultsObj = new GroupedResultsModel(groupName)
156
-
157
- content.forEach(resultEntry => {
158
- if (resultEntry.ruleId === groupName) {
159
- groupResultsObj.severity = resultEntry.severity
160
- groupResultsObj.issue = stripMustacheTags(resultEntry.issue)
161
- groupResultsObj.advice = resultEntry.advice
162
- groupResultsObj.learn = resultEntry.learn
163
- groupResultsObj.message = resultEntry.message?.text
164
-
165
- groupResultsObj.lineInfoSet.add(getMessage(resultEntry.locations))
166
- }
167
- })
168
- groupTypeResults.push(groupResultsObj)
169
- })
170
-
171
- return groupTypeResults
172
- }
173
-
174
- export function getMessage(locations: Location[]) {
175
- const message = locations[0]?.physicalLocation?.artifactLocation?.uri || ''
176
- const lineNumber = locations[0]?.physicalLocation?.region?.startLine || ''
177
-
178
- if (!lineNumber) {
179
- return '@' + message
180
- }
181
-
182
- return '@' + message + ':' + lineNumber
183
- }
184
-
185
- export function stripMustacheTags(oldString: string) {
186
- return oldString
187
- .replace(/\n/g, ' ')
188
- .replace(/{{.*?}}/g, '\n')
189
- .replace(/\$\$LINK_DELIM\$\$/g, '\n')
190
- .replace(/\s+/g, ' ')
191
- .trim()
192
- }
@@ -31,11 +31,15 @@ const getScanConfig = argv => {
31
31
  }
32
32
 
33
33
  // if no name, take the full file path and use it as the project name
34
+ let projectNameSource
34
35
  if (!scanParams.name && scanParams.file) {
35
36
  scanParams.name = getFileName(scanParams.file)
37
+ projectNameSource = 'AUTO'
38
+ } else {
39
+ projectNameSource = 'USER'
36
40
  }
37
41
 
38
- return { ...paramsAuth, ...scanParams }
42
+ return { ...paramsAuth, ...scanParams, projectNameSource }
39
43
  }
40
44
 
41
45
  const getFileName = file => {
@@ -2,7 +2,8 @@ const i18n = require('i18n')
2
2
  const {
3
3
  returnOra,
4
4
  startSpinner,
5
- succeedSpinner
5
+ succeedSpinner,
6
+ stopSpinner
6
7
  } = require('../utils/oraWrapper')
7
8
  const populateProjectIdAndProjectName = require('./populateProjectIdAndProjectName')
8
9
  const scan = require('./scan')
@@ -28,6 +29,11 @@ const fileAndLanguageLogic = async configToUse => {
28
29
  console.log(i18n.__('fileNotExist'))
29
30
  process.exit(1)
30
31
  }
32
+
33
+ if (fileFunctions.fileIsEmpty(configToUse.file)) {
34
+ console.log(i18n.__('scanFileIsEmpty'))
35
+ process.exit(1)
36
+ }
31
37
  return configToUse
32
38
  } else {
33
39
  if (configToUse.file === undefined || configToUse.file === null) {
@@ -40,10 +46,15 @@ const startScan = async configToUse => {
40
46
  const startTime = performance.now()
41
47
  await fileAndLanguageLogic(configToUse)
42
48
 
49
+ let newProject
50
+
43
51
  if (!configToUse.projectId) {
44
- configToUse.projectId = await populateProjectIdAndProjectName.populateProjectId(
45
- configToUse
46
- )
52
+ const { projectId, isNewProject } =
53
+ await populateProjectIdAndProjectName.populateProjectId(configToUse)
54
+ configToUse.projectId = projectId
55
+ newProject = isNewProject
56
+ } else {
57
+ newProject = false
47
58
  }
48
59
  const codeArtifactId = await scan.sendScan(configToUse)
49
60
 
@@ -53,6 +64,7 @@ const startScan = async configToUse => {
53
64
  const scanDetail = await scanResults.returnScanResults(
54
65
  configToUse,
55
66
  codeArtifactId,
67
+ newProject,
56
68
  getTimeout(configToUse),
57
69
  startScanSpinner
58
70
  )
@@ -64,12 +76,20 @@ const startScan = async configToUse => {
64
76
 
65
77
  const endTime = performance.now()
66
78
  const scanDurationMs = endTime - startTime
67
- succeedSpinner(startScanSpinner, 'Contrast Scan complete')
68
- console.log(
69
- `----- Scan completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`
70
- )
71
- const projectOverview = await scanResults.returnScanProjectById(configToUse)
72
- return { projectOverview, scanDetail, scanResultsInstances }
79
+ if (scanResultsInstances.statusCode !== 200) {
80
+ stopSpinner(startScanSpinner)
81
+ console.log('Result Service is unavailable, please try again later')
82
+ process.exit(1)
83
+ } else {
84
+ succeedSpinner(startScanSpinner, 'Contrast Scan complete')
85
+ console.log(
86
+ `----- Scan completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`
87
+ )
88
+ return {
89
+ scanDetail,
90
+ scanResultsInstances: scanResultsInstances.body
91
+ }
92
+ }
73
93
  }
74
94
  }
75
95
 
@@ -3,6 +3,7 @@ const requestUtils = require('../../src/utils/requestUtils')
3
3
  const oraFunctions = require('../utils/oraWrapper')
4
4
  const _ = require('lodash')
5
5
  const i18n = require('i18n')
6
+ const oraWrapper = require('../utils/oraWrapper')
6
7
 
7
8
  const getScanId = async (config, codeArtifactId, client) => {
8
9
  return client
@@ -30,11 +31,21 @@ const pollScanResults = async (config, scanId, client) => {
30
31
  const returnScanResults = async (
31
32
  config,
32
33
  codeArtifactId,
34
+ newProject,
33
35
  timeout,
34
36
  startScanSpinner
35
37
  ) => {
36
38
  const client = commonApi.getHttpClient(config)
37
39
  let scanId = await getScanId(config, codeArtifactId, client)
40
+
41
+ // send metrics event to sast-event-collector
42
+ if (
43
+ process.env.CODESEC_INVOCATION_ENVIRONMENT &&
44
+ process.env.CODESEC_INVOCATION_ENVIRONMENT.toUpperCase() === 'GITHUB'
45
+ ) {
46
+ await client.createNewEvent(config, scanId, newProject)
47
+ }
48
+
38
49
  let startTime = new Date()
39
50
  let complete = false
40
51
  if (!_.isNil(scanId)) {
@@ -47,17 +58,27 @@ const returnScanResults = async (
47
58
  }
48
59
  if (result.body.status === 'FAILED') {
49
60
  complete = true
50
- oraFunctions.failSpinner(startScanSpinner, 'Contrast Scan Failed.')
51
- console.log(result.body.errorMessage)
61
+ if (config.debug) {
62
+ oraFunctions.failSpinner(
63
+ startScanSpinner,
64
+ i18n.__(
65
+ 'scanNotCompleted',
66
+ 'https://docs.contrastsecurity.com/en/binary-package-preparation.html'
67
+ )
68
+ )
69
+ }
52
70
  if (
53
- result.body.errorMessage ===
71
+ result?.body?.errorMessage ===
54
72
  'Unable to determine language for code artifact'
55
73
  ) {
74
+ console.log(result.body.errorMessage)
56
75
  console.log(
57
76
  'Try scanning again using --language param. ',
58
77
  i18n.__('scanOptionsLanguageSummary')
59
78
  )
60
79
  }
80
+ oraWrapper.stopSpinner(startScanSpinner)
81
+ console.log('Contrast Scan Finished')
61
82
  process.exit(1)
62
83
  }
63
84
  }
@@ -80,23 +101,16 @@ const returnScanResultsInstances = async (config, scanId) => {
80
101
  try {
81
102
  result = await client.getScanResultsInstances(config, scanId)
82
103
  if (JSON.stringify(result.statusCode) == 200) {
83
- return result.body
104
+ return { body: result.body, statusCode: result.statusCode }
84
105
  }
85
- } catch (e) {
86
- console.log(e.message.toString())
87
- }
88
- }
89
106
 
90
- const returnScanProjectById = async config => {
91
- const client = commonApi.getHttpClient(config)
92
- let result
93
- try {
94
- result = await client.getScanProjectById(config)
95
- if (JSON.stringify(result.statusCode) == 200) {
96
- return result.body
107
+ if (JSON.stringify(result.statusCode) == 503) {
108
+ return { statusCode: result.statusCode }
97
109
  }
98
110
  } catch (e) {
99
- console.log(e.message.toString())
111
+ if (config.debug) {
112
+ console.log(e.message.toString())
113
+ }
100
114
  }
101
115
  }
102
116
 
@@ -104,6 +118,5 @@ module.exports = {
104
118
  getScanId: getScanId,
105
119
  returnScanResults: returnScanResults,
106
120
  pollScanResults: pollScanResults,
107
- returnScanResultsInstances: returnScanResultsInstances,
108
- returnScanProjectById: returnScanProjectById
121
+ returnScanResultsInstances: returnScanResultsInstances
109
122
  }