@contrast/contrast 1.0.6 → 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 (83) hide show
  1. package/.prettierignore +0 -6
  2. package/dist/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +4 -2
  3. package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
  4. package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
  5. package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
  6. package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +2 -0
  7. package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +10 -1
  8. package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +6 -9
  9. package/dist/audit/languageAnalysisEngine/sendSnapshot.js +65 -3
  10. package/dist/commands/audit/processAudit.js +1 -1
  11. package/dist/commands/scan/sca/scaAnalysis.js +13 -2
  12. package/dist/common/HTTPClient.js +50 -15
  13. package/dist/common/errorHandling.js +6 -1
  14. package/dist/common/versionChecker.js +1 -1
  15. package/dist/constants/constants.js +1 -1
  16. package/dist/constants/locales.js +3 -1
  17. package/dist/lambda/analytics.js +11 -0
  18. package/dist/lambda/lambda.js +35 -4
  19. package/dist/lambda/types.js +13 -0
  20. package/dist/scaAnalysis/common/formatMessage.js +17 -1
  21. package/dist/scaAnalysis/java/analysis.js +3 -6
  22. package/dist/scaAnalysis/java/index.js +2 -2
  23. package/dist/scaAnalysis/python/analysis.js +41 -0
  24. package/dist/scaAnalysis/python/index.js +10 -0
  25. package/dist/scaAnalysis/ruby/analysis.js +226 -0
  26. package/dist/scaAnalysis/ruby/index.js +10 -0
  27. package/dist/scan/autoDetection.js +6 -2
  28. package/dist/scan/fileUtils.js +14 -7
  29. package/dist/scan/formatScanOutput.js +9 -11
  30. package/dist/scan/models/groupedResultsModel.js +1 -1
  31. package/dist/scan/models/scanResultsModel.js +3 -1
  32. package/dist/scan/populateProjectIdAndProjectName.js +2 -1
  33. package/dist/scan/scan.js +1 -0
  34. package/dist/scan/scanConfig.js +6 -1
  35. package/dist/scan/scanController.js +16 -3
  36. package/dist/scan/scanResults.js +5 -1
  37. package/dist/utils/commonApi.js +4 -1
  38. package/package.json +11 -7
  39. package/src/audit/catalogueApplication/catalogueApplication.js +0 -1
  40. package/src/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +11 -8
  41. package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
  42. package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
  43. package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
  44. package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +8 -0
  45. package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +10 -9
  46. package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +34 -29
  47. package/src/audit/languageAnalysisEngine/report/models/reportLibraryModel.ts +3 -3
  48. package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +15 -11
  49. package/src/audit/languageAnalysisEngine/report/models/reportSeverityModel.ts +6 -1
  50. package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +43 -27
  51. package/src/audit/languageAnalysisEngine/sendSnapshot.js +78 -3
  52. package/src/commands/audit/processAudit.ts +1 -1
  53. package/src/commands/scan/sca/scaAnalysis.js +13 -5
  54. package/src/common/HTTPClient.js +65 -25
  55. package/src/common/errorHandling.ts +10 -1
  56. package/src/common/versionChecker.ts +1 -1
  57. package/src/constants/constants.js +1 -1
  58. package/src/constants/locales.js +3 -1
  59. package/src/lambda/analytics.ts +9 -0
  60. package/src/lambda/arn.ts +2 -1
  61. package/src/lambda/lambda.ts +37 -17
  62. package/src/lambda/types.ts +35 -0
  63. package/src/lambda/utils.ts +2 -7
  64. package/src/scaAnalysis/common/formatMessage.js +19 -1
  65. package/src/scaAnalysis/go/goAnalysis.js +2 -3
  66. package/src/scaAnalysis/java/analysis.js +5 -6
  67. package/src/scaAnalysis/java/index.js +2 -2
  68. package/src/scaAnalysis/python/analysis.js +48 -0
  69. package/src/scaAnalysis/python/index.js +11 -0
  70. package/src/scaAnalysis/ruby/analysis.js +282 -0
  71. package/src/scaAnalysis/ruby/index.js +11 -0
  72. package/src/scan/autoDetection.js +9 -5
  73. package/src/scan/fileUtils.js +15 -7
  74. package/src/scan/formatScanOutput.ts +11 -12
  75. package/src/scan/models/groupedResultsModel.ts +3 -3
  76. package/src/scan/models/resultContentModel.ts +1 -1
  77. package/src/scan/models/scanResultsModel.ts +5 -2
  78. package/src/scan/populateProjectIdAndProjectName.js +3 -1
  79. package/src/scan/scan.ts +1 -0
  80. package/src/scan/scanConfig.js +5 -1
  81. package/src/scan/scanController.js +18 -4
  82. package/src/scan/scanResults.js +10 -0
  83. package/src/utils/commonApi.js +4 -1
@@ -0,0 +1,282 @@
1
+ const fs = require('fs')
2
+
3
+ const readAndParseGemfile = projectPath => {
4
+ const fileName = filePathForWindows(projectPath + '/Gemfile')
5
+ const gemFile = fs.readFileSync(fileName, 'utf8')
6
+ const rubyArray = gemFile.split('\n')
7
+
8
+ let filteredRubyDep = rubyArray.filter(element => {
9
+ return (
10
+ !element.includes('#') &&
11
+ element.includes('gem') &&
12
+ !element.includes('source')
13
+ )
14
+ })
15
+
16
+ for (let i = 0; i < filteredRubyDep.length; i++) {
17
+ filteredRubyDep[i] = filteredRubyDep[i].trim()
18
+ }
19
+
20
+ return filteredRubyDep
21
+ }
22
+
23
+ const readAndParseGemLockFile = projectPath => {
24
+ const fileName = filePathForWindows(projectPath + '/Gemfile.lock')
25
+ const lockFile = fs.readFileSync(fileName, 'utf8')
26
+ const dependencyRegEx = /^\s*([A-Za-z0-9.!@#$%\-^&*_+]*)\s*(\((.*?)\))/
27
+
28
+ const lines = lockFile.split('\n')
29
+
30
+ return {
31
+ dependencies: getDirectDependencies(lines, dependencyRegEx),
32
+ runtimeDetails: getLockFileRuntimeInfo(lines),
33
+ sources: getSourceArray(lines, dependencyRegEx)
34
+ }
35
+ }
36
+
37
+ const nonDependencyKeys = (line, sourceObject) => {
38
+ const GEMFILE_KEY_VALUE = /^\s*([^:(]*)\s*\s*(.*)/
39
+ let parts = GEMFILE_KEY_VALUE.exec(line)
40
+ let key = parts[1].trim()
41
+ let value = parts[2] || ''
42
+
43
+ sourceObject[key] = value
44
+ return sourceObject
45
+ }
46
+
47
+ const populateResolveAndPlatform = (version, sourceObject) => {
48
+ const depArr = version.split('-')
49
+ sourceObject.resolved = depArr[0]
50
+ sourceObject.platform = depArr.length > 1 ? depArr[1] : 'UNSPECIFIED'
51
+ return sourceObject
52
+ }
53
+
54
+ const isUpperCase = str => {
55
+ return str === str.toUpperCase()
56
+ }
57
+
58
+ const getDirectDependencies = (lines, dependencyRegEx) => {
59
+ const dependencies = {}
60
+
61
+ let depIndex = 0
62
+ for (let i = 0; i < lines.length; i++) {
63
+ if (lines[i] === 'DEPENDENCIES') {
64
+ depIndex = i
65
+ }
66
+ }
67
+ const getDepArray = lines.slice(depIndex)
68
+
69
+ for (let j = 1; j < getDepArray.length; j++) {
70
+ const element = getDepArray[j]
71
+ if (!isUpperCase(element)) {
72
+ const isDependencyWithVersion = dependencyRegEx.test(element)
73
+ if (isDependencyWithVersion) {
74
+ const dependency = dependencyRegEx.exec(element)
75
+ let name = dependency[1]
76
+ name = name.replace('!', '')
77
+ dependencies[name.trim()] = dependency[3]
78
+ } else {
79
+ let name = element
80
+ name = name.replace('!', ' ')
81
+ dependencies[name.trim()] = 'UNSPECIFIED'
82
+ }
83
+ }
84
+ }
85
+
86
+ return dependencies
87
+ }
88
+
89
+ const getLockFileRuntimeInfo = lines => {
90
+ let rubVersionIndex = 0
91
+ for (let i = 0; i < lines.length; i++) {
92
+ if (lines[i] === 'RUBY VERSION') {
93
+ rubVersionIndex = i
94
+ break
95
+ }
96
+ }
97
+
98
+ const runtimeDetails = {}
99
+ if (rubVersionIndex !== 0) {
100
+ const getRubyVersionArray = lines.slice(rubVersionIndex)
101
+
102
+ for (let element of getRubyVersionArray) {
103
+ if (!isUpperCase(element)) {
104
+ runtimeDetails['version'] = getVersion(element)
105
+ runtimeDetails['patchLevel'] = getPatchLevel(element)
106
+
107
+ if (element.includes('engine')) {
108
+ let splitElement = element.split(' ')
109
+ runtimeDetails[splitElement[0]] = splitElement[1]
110
+ }
111
+ }
112
+ }
113
+ }
114
+ return runtimeDetails
115
+ }
116
+
117
+ const getVersion = element => {
118
+ const versionRegex = /^([ruby\s0-9.*]+)/
119
+ if (versionRegex.test(element)) {
120
+ let version = versionRegex.exec(element)[0]
121
+
122
+ if (version.includes('ruby')) {
123
+ return trimWhiteSpace(version.replace('ruby', ''))
124
+ }
125
+ }
126
+ }
127
+
128
+ const getPatchLevel = element => {
129
+ const patchLevelRegex = /(p\d+)/
130
+ if (patchLevelRegex.test(element)) {
131
+ return patchLevelRegex.exec(element)[0]
132
+ }
133
+ }
134
+
135
+ const formatSourceArr = sourceArr => {
136
+ return sourceArr.map(element => {
137
+ if (element.sourceType === 'GIT') {
138
+ delete element.specs
139
+ }
140
+
141
+ if (element.sourceType === 'GEM') {
142
+ delete element.branch
143
+ delete element.revision
144
+ delete element.depthLevel
145
+ delete element.specs
146
+ }
147
+
148
+ if (element.sourceType === 'PATH') {
149
+ delete element.branch
150
+ delete element.revision
151
+ delete element.depthLevel
152
+ delete element.specs
153
+ delete element.platform
154
+ }
155
+ return element
156
+ })
157
+ }
158
+
159
+ const getSourceArray = (lines, dependencyRegEx) => {
160
+ const sourceObject = {
161
+ dependencies: {}
162
+ }
163
+
164
+ const whitespaceRegx = /^(\s*)/
165
+ let index = 0
166
+
167
+ let line = 0
168
+ const sources = []
169
+ while ((line = lines[index++]) !== undefined) {
170
+ let currentWS = whitespaceRegx.exec(line)[1].length
171
+ if (!line.includes(' bundler (')) {
172
+ if (currentWS === 0 && !line.includes(':') && line !== '') {
173
+ sourceObject.sourceType = line
174
+ }
175
+
176
+ if (currentWS !== 0 && line.includes(':')) {
177
+ nonDependencyKeys(line, sourceObject)
178
+ }
179
+
180
+ if (currentWS > 2) {
181
+ let nexlineWS = whitespaceRegx.exec(lines[index])[1].length
182
+ sourceObject.dependencies = buildSourceDependencyWithVersion(
183
+ whitespaceRegx,
184
+ dependencyRegEx,
185
+ line,
186
+ currentWS,
187
+ sourceObject.name,
188
+ sourceObject.dependencies
189
+ )
190
+
191
+ if (currentWS === 4 && sourceObject.depthLevel === undefined) {
192
+ const dependency = dependencyRegEx.exec(line)
193
+ sourceObject.name = dependency[1]
194
+ sourceObject.depthLevel = currentWS
195
+ populateResolveAndPlatform(dependency[3], sourceObject)
196
+ }
197
+
198
+ if (currentWS === 4 && sourceObject.depthLevel) {
199
+ // create new Parent
200
+ const dependency = dependencyRegEx.exec(line)
201
+ sourceObject.name = dependency[1]
202
+ sourceObject.depthLevel = currentWS
203
+ populateResolveAndPlatform(dependency[3], sourceObject)
204
+ }
205
+
206
+ if (
207
+ (currentWS === 4 && nexlineWS === 4) ||
208
+ (currentWS === 6 && nexlineWS === 4) ||
209
+ nexlineWS === ''
210
+ ) {
211
+ let newObj = {}
212
+ newObj = JSON.parse(JSON.stringify(sourceObject))
213
+ sources.push(newObj)
214
+ sourceObject.dependencies = {}
215
+ }
216
+ }
217
+ }
218
+ }
219
+ return formatSourceArr(sources)
220
+ }
221
+
222
+ const buildSourceDependencyWithVersion = (
223
+ whitespaceRegx,
224
+ dependencyRegEx,
225
+ line,
226
+ currentWhiteSpace,
227
+ name,
228
+ dependencies
229
+ ) => {
230
+ const isDependencyWithVersion = dependencyRegEx.test(line)
231
+
232
+ if (currentWhiteSpace === 6) {
233
+ const dependency = dependencyRegEx.exec(line)
234
+ if (isDependencyWithVersion) {
235
+ if (name !== dependency[1]) {
236
+ dependencies[dependency[1]] = dependency[3]
237
+ }
238
+ } else {
239
+ dependencies[line.trim()] = 'UNSPECIFIED'
240
+ }
241
+ }
242
+
243
+ return dependencies
244
+ }
245
+
246
+ const getRubyDeps = config => {
247
+ try {
248
+ const parsedGem = readAndParseGemfile(config.projectPath)
249
+ const parsedLock = readAndParseGemLockFile(config.projectPath)
250
+
251
+ return { gemfilesDependanceies: parsedGem, gemfileLock: parsedLock }
252
+ } catch (err) {
253
+ console.log(err.message)
254
+ process.exit(1)
255
+ }
256
+ }
257
+
258
+ const trimWhiteSpace = string => {
259
+ return string.replace(/\s+/g, '')
260
+ }
261
+
262
+ const filePathForWindows = path => {
263
+ if (process.platform === 'win32') {
264
+ path = path.replace(/\//g, '\\')
265
+ }
266
+ return path
267
+ }
268
+
269
+ module.exports = {
270
+ getRubyDeps,
271
+ readAndParseGemfile,
272
+ readAndParseGemLockFile,
273
+ nonDependencyKeys,
274
+ populateResolveAndPlatform,
275
+ isUpperCase,
276
+ getDirectDependencies,
277
+ getLockFileRuntimeInfo,
278
+ getVersion,
279
+ getPatchLevel,
280
+ formatSourceArr,
281
+ getSourceArray
282
+ }
@@ -0,0 +1,11 @@
1
+ const { getRubyDeps } = require('./analysis')
2
+ const { createRubyTSMessage } = require('../common/formatMessage')
3
+
4
+ const rubyAnalysis = (config, languageFiles) => {
5
+ const rubyDeps = getRubyDeps(config, languageFiles.RUBY)
6
+ return createRubyTSMessage(rubyDeps)
7
+ }
8
+
9
+ module.exports = {
10
+ rubyAnalysis
11
+ }
@@ -14,6 +14,11 @@ const autoDetectFileAndLanguage = async configToUse => {
14
14
  process.exit(1)
15
15
  }
16
16
 
17
+ if (fileFinder.fileIsEmpty(entries[0])) {
18
+ console.log(i18n.__('scanFileIsEmpty'))
19
+ process.exit(1)
20
+ }
21
+
17
22
  configToUse.file = entries[0]
18
23
  if (configToUse.name === undefined) {
19
24
  configToUse.name = entries[0]
@@ -43,11 +48,10 @@ const autoDetectAuditFilesAndLanguages = async () => {
43
48
  }
44
49
  }
45
50
 
46
- const manualDetectAuditFilesAndLanguages = async projectPath => {
47
- let projectRootFilenames = await rootFile.getProjectRootFilenames(projectPath)
48
- let identifiedLanguages = languageResolver.deduceLanguageScaAnalysis(
49
- projectRootFilenames
50
- )
51
+ const manualDetectAuditFilesAndLanguages = projectPath => {
52
+ let projectRootFilenames = rootFile.getProjectRootFilenames(projectPath)
53
+ let identifiedLanguages =
54
+ languageResolver.deduceLanguageScaAnalysis(projectRootFilenames)
51
55
 
52
56
  if (Object.keys(identifiedLanguages).length === 0) {
53
57
  console.log(i18n.__('languageAnalysisNoLanguage', projectPath))
@@ -22,7 +22,7 @@ const findFilesJava = async languagesFound => {
22
22
  )
23
23
 
24
24
  if (result.length > 0) {
25
- return languagesFound.push({ java: result })
25
+ return languagesFound.push({ JAVA: result })
26
26
  }
27
27
  return languagesFound
28
28
  }
@@ -38,7 +38,7 @@ const findFilesJavascript = async languagesFound => {
38
38
  )
39
39
 
40
40
  if (result.length > 0) {
41
- return languagesFound.push({ javascript: result })
41
+ return languagesFound.push({ JAVASCRIPT: result })
42
42
  }
43
43
  return languagesFound
44
44
  }
@@ -51,7 +51,7 @@ const findFilesPython = async languagesFound => {
51
51
  })
52
52
 
53
53
  if (result.length > 0) {
54
- return languagesFound.push({ python: result })
54
+ return languagesFound.push({ PYTHON: result })
55
55
  }
56
56
  return languagesFound
57
57
  }
@@ -64,7 +64,7 @@ const findFilesGo = async languagesFound => {
64
64
  })
65
65
 
66
66
  if (result.length > 0) {
67
- return languagesFound.push({ go: result })
67
+ return languagesFound.push({ GO: result })
68
68
  }
69
69
  return languagesFound
70
70
  }
@@ -77,7 +77,7 @@ const findFilesRuby = async languagesFound => {
77
77
  })
78
78
 
79
79
  if (result.length > 0) {
80
- return languagesFound.push({ ruby: result })
80
+ return languagesFound.push({ RUBY: result })
81
81
  }
82
82
  return languagesFound
83
83
  }
@@ -90,7 +90,7 @@ const findFilesPhp = async languagesFound => {
90
90
  })
91
91
 
92
92
  if (result.length > 0) {
93
- return languagesFound.push({ php: result })
93
+ return languagesFound.push({ PHP: result })
94
94
  }
95
95
  return languagesFound
96
96
  }
@@ -110,6 +110,13 @@ const fileExists = path => {
110
110
  return fs.existsSync(path)
111
111
  }
112
112
 
113
+ const fileIsEmpty = path => {
114
+ if (fileExists(path) && checkFilePermissions(path)) {
115
+ return fs.readFileSync(path).length === 0
116
+ }
117
+ return false
118
+ }
119
+
113
120
  module.exports = {
114
121
  findFile,
115
122
  fileExists,
@@ -119,5 +126,6 @@ module.exports = {
119
126
  findFilesPython,
120
127
  findFilesGo,
121
128
  findFilesPhp,
122
- findFilesRuby
129
+ findFilesRuby,
130
+ fileIsEmpty
123
131
  }
@@ -1,5 +1,4 @@
1
1
  import {
2
- ProjectOverview,
3
2
  ScanResultsInstances,
4
3
  ScanResultsModel
5
4
  } from './models/scanResultsModel'
@@ -20,7 +19,7 @@ import {
20
19
  export function formatScanOutput(scanResults: ScanResultsModel) {
21
20
  const { scanResultsInstances } = scanResults
22
21
 
23
- let projectOverview = getProjectOverview(scanResultsInstances)
22
+ const projectOverview = getProjectOverview(scanResultsInstances)
24
23
  if (scanResultsInstances.content.length === 0) {
25
24
  console.log(i18n.__('scanNoVulnerabilitiesFound'))
26
25
  console.log(i18n.__('scanNoVulnerabilitiesFoundSecureCode'))
@@ -62,7 +61,7 @@ export function formatScanOutput(scanResults: ScanResultsModel) {
62
61
  })
63
62
  let learnRow: string[] = []
64
63
  let adviceRow = []
65
- let headerRow = [
64
+ const headerRow = [
66
65
  chalk
67
66
  .hex(entry.colour)
68
67
  .bold(`CONTRAST-${count.toString().padStart(3, '0')}`),
@@ -70,12 +69,15 @@ export function formatScanOutput(scanResults: ScanResultsModel) {
70
69
  chalk.hex(entry.colour).bold(`[${entry.severity}] ${entry.ruleId}`) +
71
70
  entry.message
72
71
  ]
73
- let codeRow = [
72
+
73
+ const codePath = entry.codePath?.replace(/^@/, '')
74
+
75
+ const codeRow = [
74
76
  chalk.hex('#F6F5F5').bold(`Code`),
75
77
  chalk.hex('#F6F5F5').bold(`:`),
76
- chalk.hex('#F6F5F5').bold(`${entry.codePath}`)
78
+ chalk.hex('#F6F5F5').bold(`${codePath}`)
77
79
  ]
78
- let issueRow = [chalk.bold(`Issue`), chalk.bold(`:`), `${entry.issue}`]
80
+ const issueRow = [chalk.bold(`Issue`), chalk.bold(`:`), `${entry.issue}`]
79
81
 
80
82
  table.push(headerRow, codeRow, issueRow)
81
83
 
@@ -123,7 +125,7 @@ function printVulnInfo(projectOverview: any) {
123
125
  }
124
126
 
125
127
  export function getProjectOverview(scanResultsInstances: ScanResultsInstances) {
126
- let acc: any = {
128
+ const acc: any = {
127
129
  critical: 0,
128
130
  high: 0,
129
131
  medium: 0,
@@ -146,7 +148,7 @@ export function getProjectOverview(scanResultsInstances: ScanResultsInstances) {
146
148
  }
147
149
 
148
150
  export function formatLinks(objName: string, entry: any[]) {
149
- let line = chalk.bold(objName + ' : ')
151
+ const line = chalk.bold(objName + ' : ')
150
152
  if (entry.length === 1) {
151
153
  console.log(line + chalk.hex('#97DCF7').bold.underline(entry[0]))
152
154
  } else {
@@ -216,10 +218,7 @@ export function getCodeFlowInfo(resultEntry: ResultContent) {
216
218
  }
217
219
 
218
220
  export function stripTags(oldString: string) {
219
- return oldString
220
- .replace(/\n/g, ' ')
221
- .replace(/\s+/g, ' ')
222
- .trim()
221
+ return oldString.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim()
223
222
  }
224
223
 
225
224
  export function assignBySeverity(
@@ -9,12 +9,12 @@ export class GroupedResultsModel {
9
9
  issue?: string
10
10
  priority?: number
11
11
  message?: string | undefined
12
- colour: string;
13
- codePath?: string;
12
+ colour: string
13
+ codePath?: string
14
14
 
15
15
  constructor(ruleId: string) {
16
16
  this.ruleId = ruleId
17
17
  this.colour = '#999999'
18
- this.codePathSet = new Set<string>
18
+ this.codePathSet = new Set<string>()
19
19
  }
20
20
  }
@@ -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
@@ -57,6 +57,7 @@ export const sendScan = async (config: any) => {
57
57
  }
58
58
  })
59
59
  .catch(err => {
60
+ oraWrapper.stopSpinner(startUploadSpinner)
60
61
  console.log(err)
61
62
  })
62
63
  }
@@ -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 => {
@@ -29,6 +29,11 @@ const fileAndLanguageLogic = async configToUse => {
29
29
  console.log(i18n.__('fileNotExist'))
30
30
  process.exit(1)
31
31
  }
32
+
33
+ if (fileFunctions.fileIsEmpty(configToUse.file)) {
34
+ console.log(i18n.__('scanFileIsEmpty'))
35
+ process.exit(1)
36
+ }
32
37
  return configToUse
33
38
  } else {
34
39
  if (configToUse.file === undefined || configToUse.file === null) {
@@ -41,10 +46,15 @@ const startScan = async configToUse => {
41
46
  const startTime = performance.now()
42
47
  await fileAndLanguageLogic(configToUse)
43
48
 
49
+ let newProject
50
+
44
51
  if (!configToUse.projectId) {
45
- configToUse.projectId = await populateProjectIdAndProjectName.populateProjectId(
46
- configToUse
47
- )
52
+ const { projectId, isNewProject } =
53
+ await populateProjectIdAndProjectName.populateProjectId(configToUse)
54
+ configToUse.projectId = projectId
55
+ newProject = isNewProject
56
+ } else {
57
+ newProject = false
48
58
  }
49
59
  const codeArtifactId = await scan.sendScan(configToUse)
50
60
 
@@ -54,6 +64,7 @@ const startScan = async configToUse => {
54
64
  const scanDetail = await scanResults.returnScanResults(
55
65
  configToUse,
56
66
  codeArtifactId,
67
+ newProject,
57
68
  getTimeout(configToUse),
58
69
  startScanSpinner
59
70
  )
@@ -74,7 +85,10 @@ const startScan = async configToUse => {
74
85
  console.log(
75
86
  `----- Scan completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`
76
87
  )
77
- return { scanDetail, scanResultsInstances: scanResultsInstances.body }
88
+ return {
89
+ scanDetail,
90
+ scanResultsInstances: scanResultsInstances.body
91
+ }
78
92
  }
79
93
  }
80
94
  }
@@ -31,11 +31,21 @@ const pollScanResults = async (config, scanId, client) => {
31
31
  const returnScanResults = async (
32
32
  config,
33
33
  codeArtifactId,
34
+ newProject,
34
35
  timeout,
35
36
  startScanSpinner
36
37
  ) => {
37
38
  const client = commonApi.getHttpClient(config)
38
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
+
39
49
  let startTime = new Date()
40
50
  let complete = false
41
51
  if (!_.isNil(scanId)) {
@@ -4,7 +4,8 @@ const {
4
4
  unauthenticatedError,
5
5
  forbiddenError,
6
6
  proxyError,
7
- genericError
7
+ genericError,
8
+ maxAppError
8
9
  } = require('../common/errorHandling')
9
10
 
10
11
  const handleResponseErrors = (res, api) => {
@@ -16,6 +17,8 @@ const handleResponseErrors = (res, api) => {
16
17
  forbiddenError()
17
18
  } else if (res.statusCode === 407) {
18
19
  proxyError()
20
+ } else if (res.statusCode === 412) {
21
+ maxAppError()
19
22
  } else {
20
23
  genericError()
21
24
  }