@contrast/contrast 1.0.9 → 1.0.12

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 (108) hide show
  1. package/README.md +2 -2
  2. package/dist/audit/languageAnalysisEngine/getProjectRootFilenames.js +17 -17
  3. package/dist/audit/{languageAnalysisEngine/report → report}/commonReportingFunctions.js +56 -35
  4. package/dist/audit/report/models/reportGuidanceModel.js +6 -0
  5. package/dist/audit/{languageAnalysisEngine/report → report}/models/reportLibraryModel.js +0 -0
  6. package/dist/audit/{languageAnalysisEngine/report → report}/models/reportListModel.js +0 -0
  7. package/dist/audit/{languageAnalysisEngine/report → report}/models/reportOutputModel.js +1 -2
  8. package/dist/audit/{languageAnalysisEngine/report → report}/models/reportSeverityModel.js +0 -0
  9. package/dist/audit/{languageAnalysisEngine/report → report}/models/severityCountModel.js +1 -0
  10. package/dist/audit/{languageAnalysisEngine/report → report}/reportingFeature.js +12 -8
  11. package/dist/audit/{languageAnalysisEngine/report → report}/utils/reportUtils.js +3 -4
  12. package/dist/commands/audit/auditConfig.js +3 -3
  13. package/dist/commands/audit/help.js +3 -1
  14. package/dist/commands/audit/processAudit.js +4 -2
  15. package/dist/commands/auth/auth.js +1 -1
  16. package/dist/commands/config/config.js +2 -2
  17. package/dist/commands/scan/processScan.js +11 -4
  18. package/dist/commands/scan/sca/scaAnalysis.js +20 -9
  19. package/dist/common/HTTPClient.js +9 -0
  20. package/dist/common/commonHelp.js +19 -0
  21. package/dist/common/errorHandling.js +2 -2
  22. package/dist/common/fail.js +66 -0
  23. package/dist/common/versionChecker.js +4 -2
  24. package/dist/constants/constants.js +2 -2
  25. package/dist/constants/locales.js +26 -11
  26. package/dist/constants.js +52 -5
  27. package/dist/index.js +5 -2
  28. package/dist/lambda/help.js +2 -3
  29. package/dist/scaAnalysis/common/scaParserForGoAndJava.js +32 -0
  30. package/dist/scaAnalysis/common/treeUpload.js +20 -5
  31. package/dist/scaAnalysis/dotnet/analysis.js +15 -3
  32. package/dist/scaAnalysis/go/goAnalysis.js +8 -2
  33. package/dist/scaAnalysis/java/analysis.js +10 -6
  34. package/dist/scaAnalysis/java/index.js +7 -1
  35. package/dist/scaAnalysis/java/javaBuildDepsParser.js +19 -3
  36. package/dist/scaAnalysis/javascript/index.js +3 -0
  37. package/dist/scaAnalysis/php/analysis.js +1 -1
  38. package/dist/scaAnalysis/php/index.js +12 -6
  39. package/dist/scaAnalysis/php/phpNewServicesMapper.js +62 -0
  40. package/dist/scaAnalysis/python/analysis.js +43 -5
  41. package/dist/scaAnalysis/python/index.js +7 -2
  42. package/dist/scaAnalysis/ruby/analysis.js +14 -4
  43. package/dist/scan/autoDetection.js +5 -13
  44. package/dist/scan/formatScanOutput.js +6 -5
  45. package/dist/scan/help.js +2 -3
  46. package/dist/scan/populateProjectIdAndProjectName.js +5 -0
  47. package/dist/scan/scan.js +4 -0
  48. package/dist/scan/scanConfig.js +4 -4
  49. package/dist/scan/scanResults.js +46 -3
  50. package/dist/telemetry/telemetry.js +137 -0
  51. package/dist/utils/commonApi.js +1 -1
  52. package/dist/utils/getConfig.js +2 -4
  53. package/dist/utils/parsedCLIOptions.js +3 -1
  54. package/dist/utils/requestUtils.js +7 -1
  55. package/package.json +4 -2
  56. package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +22 -29
  57. package/src/audit/{languageAnalysisEngine/report → report}/commonReportingFunctions.ts +80 -44
  58. package/src/audit/report/models/reportGuidanceModel.ts +5 -0
  59. package/src/audit/{languageAnalysisEngine/report → report}/models/reportLibraryModel.ts +0 -0
  60. package/src/audit/{languageAnalysisEngine/report → report}/models/reportListModel.ts +0 -0
  61. package/src/audit/{languageAnalysisEngine/report → report}/models/reportOutputModel.ts +1 -7
  62. package/src/audit/{languageAnalysisEngine/report → report}/models/reportSeverityModel.ts +0 -0
  63. package/src/audit/{languageAnalysisEngine/report → report}/models/severityCountModel.ts +2 -0
  64. package/src/audit/{languageAnalysisEngine/report → report}/reportingFeature.ts +16 -9
  65. package/src/audit/{languageAnalysisEngine/report → report}/utils/reportUtils.ts +4 -4
  66. package/src/commands/audit/auditConfig.ts +10 -3
  67. package/src/commands/audit/help.ts +3 -1
  68. package/src/commands/audit/processAudit.ts +16 -2
  69. package/src/commands/auth/auth.js +3 -1
  70. package/src/commands/config/config.js +4 -2
  71. package/src/commands/scan/processScan.js +18 -4
  72. package/src/commands/scan/sca/scaAnalysis.js +27 -10
  73. package/src/common/HTTPClient.js +15 -0
  74. package/src/common/commonHelp.ts +13 -0
  75. package/src/common/errorHandling.ts +2 -3
  76. package/src/common/fail.js +75 -0
  77. package/src/common/versionChecker.ts +4 -4
  78. package/src/constants/constants.js +2 -2
  79. package/src/constants/locales.js +35 -13
  80. package/src/constants.js +56 -6
  81. package/src/index.ts +17 -2
  82. package/src/lambda/help.ts +2 -3
  83. package/src/scaAnalysis/common/scaParserForGoAndJava.js +41 -0
  84. package/src/scaAnalysis/common/treeUpload.js +21 -5
  85. package/src/scaAnalysis/dotnet/analysis.js +21 -3
  86. package/src/scaAnalysis/go/goAnalysis.js +9 -2
  87. package/src/scaAnalysis/java/analysis.js +11 -6
  88. package/src/scaAnalysis/java/index.js +9 -1
  89. package/src/scaAnalysis/java/javaBuildDepsParser.js +25 -6
  90. package/src/scaAnalysis/javascript/index.js +3 -0
  91. package/src/scaAnalysis/php/analysis.js +1 -1
  92. package/src/scaAnalysis/php/index.js +12 -6
  93. package/src/scaAnalysis/php/phpNewServicesMapper.js +77 -0
  94. package/src/scaAnalysis/python/analysis.js +49 -5
  95. package/src/scaAnalysis/python/index.js +7 -2
  96. package/src/scaAnalysis/ruby/analysis.js +16 -4
  97. package/src/scan/autoDetection.js +6 -13
  98. package/src/scan/formatScanOutput.ts +7 -5
  99. package/src/scan/help.js +2 -3
  100. package/src/scan/populateProjectIdAndProjectName.js +5 -1
  101. package/src/scan/scan.ts +4 -0
  102. package/src/scan/scanConfig.js +6 -4
  103. package/src/scan/scanResults.js +52 -3
  104. package/src/telemetry/telemetry.ts +154 -0
  105. package/src/utils/commonApi.js +1 -1
  106. package/src/utils/getConfig.ts +2 -11
  107. package/src/utils/parsedCLIOptions.js +14 -1
  108. package/src/utils/requestUtils.js +8 -1
@@ -14,14 +14,14 @@ const parseBuildDeps = (config, input) => {
14
14
  const preParser = shavedOutput => {
15
15
  let obj = []
16
16
  for (let dep in shavedOutput) {
17
+ shavedOutput[dep] = shaveDependencyType(shavedOutput[dep])
18
+
17
19
  obj.push(
18
20
  shavedOutput[dep]
19
21
  .replace('+-', '+---')
20
22
  .replace('[INFO]', '')
21
23
  .replace('\\-', '\\---')
22
24
  .replace(':jar:', ':')
23
- .replace(':test', '')
24
- .replace(':compile', '')
25
25
  .replace(' +', '+')
26
26
  .replace(' |', '|')
27
27
  .replace(' \\', '\\')
@@ -56,11 +56,29 @@ const preParser = shavedOutput => {
56
56
  return depTree
57
57
  }
58
58
 
59
+ const shaveDependencyType = dep => {
60
+ if (dep.endsWith('\r')) {
61
+ dep = dep.slice(0, -1)
62
+ }
63
+
64
+ if (dep.endsWith(':test')) {
65
+ dep = dep.slice(0, -5)
66
+ }
67
+
68
+ if (dep.endsWith(':compile')) {
69
+ dep = dep.slice(0, -8)
70
+ }
71
+
72
+ if (dep.endsWith(':provided')) {
73
+ dep = dep.slice(0, -9)
74
+ }
75
+
76
+ return dep
77
+ }
78
+
59
79
  const shaveOutput = (gradleDependencyTreeOutput, projectType) => {
60
80
  let shavedOutput = gradleDependencyTreeOutput.split('\n')
61
81
 
62
- // console.log(projectType)
63
-
64
82
  if (projectType === 'maven') {
65
83
  shavedOutput = preParser(shavedOutput)
66
84
  }
@@ -375,7 +393,6 @@ const validateIndentation = shavedOutput => {
375
393
 
376
394
  const parseGradle = (gradleDependencyTreeOutput, config, projectType) => {
377
395
  let shavedOutput = shaveOutput(gradleDependencyTreeOutput, projectType)
378
-
379
396
  if (config.subProject) {
380
397
  let subProject = parseSubProject(shavedOutput)
381
398
  let validatedOutput = validateIndentation(subProject)
@@ -400,5 +417,7 @@ module.exports = {
400
417
  computeRelationToLastElement,
401
418
  addIndentation,
402
419
  computeLevel,
403
- computeIndentation
420
+ computeIndentation,
421
+ shaveDependencyType,
422
+ preParser
404
423
  }
@@ -5,6 +5,9 @@ const formatMessage = require('../common/formatMessage')
5
5
  const jsAnalysis = async (config, languageFiles) => {
6
6
  checkForCorrectFiles(languageFiles)
7
7
 
8
+ if (!config.file.endsWith('/')) {
9
+ config.file = config.file.concat('/')
10
+ }
8
11
  return buildNodeTree(config, languageFiles.JAVASCRIPT)
9
12
  }
10
13
  const buildNodeTree = async (config, files) => {
@@ -5,7 +5,7 @@ const _ = require('lodash')
5
5
  const readFile = (config, nameOfFile) => {
6
6
  if (config.file) {
7
7
  try {
8
- return fs.readFileSync(config.file + '/' + nameOfFile)
8
+ return fs.readFileSync(config.file + '/' + nameOfFile, 'utf8')
9
9
  } catch (error) {
10
10
  console.log('Unable to find file')
11
11
  console.log(error)
@@ -1,13 +1,19 @@
1
1
  const { readFile, parseProjectFiles } = require('./analysis')
2
2
  const { createPhpTSMessage } = require('../common/formatMessage')
3
+ const { parsePHPLockFileForScaServices } = require('./phpNewServicesMapper')
3
4
 
4
- const phpAnalysis = (config, files) => {
5
- let analysis = readFiles(config, files.PHP)
6
- const phpDep = parseProjectFiles(analysis)
7
- return createPhpTSMessage(phpDep)
5
+ const phpAnalysis = config => {
6
+ let analysis = readFiles(config)
7
+
8
+ if (config.experimental) {
9
+ return parsePHPLockFileForScaServices(analysis.rawLockFileContents)
10
+ } else {
11
+ const phpDep = parseProjectFiles(analysis)
12
+ return createPhpTSMessage(phpDep)
13
+ }
8
14
  }
9
15
 
10
- const readFiles = (config, files) => {
16
+ const readFiles = config => {
11
17
  let php = {}
12
18
 
13
19
  php.composerJSON = JSON.parse(readFile(config, 'composer.json'))
@@ -18,5 +24,5 @@ const readFiles = (config, files) => {
18
24
  }
19
25
 
20
26
  module.exports = {
21
- phpAnalysis
27
+ phpAnalysis: phpAnalysis
22
28
  }
@@ -0,0 +1,77 @@
1
+ const { keyBy, merge } = require('lodash')
2
+
3
+ const parsePHPLockFileForScaServices = phpLockFile => {
4
+ const packages = keyBy(phpLockFile.packages, 'name')
5
+ const packagesDev = keyBy(phpLockFile['packages-dev'], 'name')
6
+
7
+ return merge(buildDepTree(packages, true), buildDepTree(packagesDev, false))
8
+ }
9
+
10
+ const buildDepTree = (packages, isProduction) => {
11
+ //builds deps into flat structure
12
+ const dependencyTree = {}
13
+
14
+ for (const packagesKey in packages) {
15
+ const currentObj = packages[packagesKey]
16
+ const { group, name } = findGroupAndName(currentObj.name)
17
+
18
+ const key = `${group}/${name}@${currentObj.version}`
19
+ dependencyTree[key] = {
20
+ group: group,
21
+ name: name,
22
+ version: currentObj.version,
23
+ directDependency: true,
24
+ isProduction: isProduction,
25
+ dependencies: []
26
+ }
27
+
28
+ const mergedChildDeps = merge(
29
+ buildSubDepsIntoFlatStructure(currentObj.require),
30
+ buildSubDepsIntoFlatStructure(currentObj['require-dev'])
31
+ )
32
+
33
+ for (const childKey in mergedChildDeps) {
34
+ const { group, name } = findGroupAndName(childKey)
35
+ const builtKey = `${group}/${name}`
36
+ dependencyTree[builtKey] = mergedChildDeps[childKey]
37
+ }
38
+ }
39
+ return dependencyTree
40
+ }
41
+
42
+ // currently sub deps will be built into a flat structure
43
+ // but not ingested via the new services as they do not have concrete versions
44
+ const buildSubDepsIntoFlatStructure = childDeps => {
45
+ const dependencyTree = {}
46
+
47
+ for (const dep in childDeps) {
48
+ const version = childDeps[dep]
49
+ const { group, name } = findGroupAndName(dep)
50
+ const key = `${group}/${name}`
51
+ dependencyTree[key] = {
52
+ group: group,
53
+ name: name,
54
+ version: version,
55
+ directDependency: false,
56
+ isProduction: false,
57
+ dependencies: []
58
+ }
59
+ }
60
+ return dependencyTree
61
+ }
62
+
63
+ const findGroupAndName = groupAndName => {
64
+ if (groupAndName.includes('/')) {
65
+ const groupName = groupAndName.split('/')
66
+ return { group: groupName[0], name: groupName[1] }
67
+ } else {
68
+ return { group: groupAndName, name: groupAndName }
69
+ }
70
+ }
71
+
72
+ module.exports = {
73
+ parsePHPLockFileForScaServices,
74
+ buildDepTree,
75
+ buildSubDepsIntoFlatStructure,
76
+ findGroupAndName
77
+ }
@@ -1,5 +1,6 @@
1
1
  const multiReplace = require('string-multiple-replace')
2
2
  const fs = require('fs')
3
+ const i18n = require('i18n')
3
4
 
4
5
  const readAndParseProjectFile = file => {
5
6
  const filePath = filePathForWindows(file + '/Pipfile')
@@ -23,12 +24,52 @@ const readAndParseLockFile = file => {
23
24
  return parsedPipLock
24
25
  }
25
26
 
26
- const getPythonDeps = config => {
27
+ const readLockFile = file => {
28
+ const filePath = filePathForWindows(file + '/Pipfile.lock')
29
+ const lockFile = fs.readFileSync(filePath, 'utf8')
30
+ let parsedPipLock = JSON.parse(lockFile)
31
+ return parsedPipLock['default']
32
+ }
33
+
34
+ const scaPythonParser = pythonDependencies => {
35
+ let pythonParsedDeps = {}
36
+ for (let key in pythonDependencies) {
37
+ pythonParsedDeps[key] = {}
38
+ pythonParsedDeps[key].version = pythonDependencies[key].version.replace(
39
+ '==',
40
+ ''
41
+ )
42
+ pythonParsedDeps[key].group = null
43
+ pythonParsedDeps[key].name = key
44
+ pythonParsedDeps[key].isProduction = true
45
+ pythonParsedDeps[key].dependencies = []
46
+ pythonParsedDeps[key].directDependency = true
47
+ }
48
+ return pythonParsedDeps
49
+ }
50
+
51
+ const checkForCorrectFiles = languageFiles => {
52
+ if (!languageFiles.includes('Pipfile.lock')) {
53
+ throw new Error(i18n.__('languageAnalysisHasNoLockFile', 'python'))
54
+ }
55
+
56
+ if (!languageFiles.includes('Pipfile')) {
57
+ throw new Error(i18n.__('languageAnalysisProjectFileError', 'python'))
58
+ }
59
+ }
60
+
61
+ const getPythonDeps = (config, languageFiles) => {
27
62
  try {
28
- const parseProject = readAndParseProjectFile(config.file)
29
- const parsePip = readAndParseLockFile(config.file)
63
+ if (config.experimental) {
64
+ let pythonLockFileContents = readLockFile(config.file)
65
+ return scaPythonParser(pythonLockFileContents)
66
+ } else {
67
+ checkForCorrectFiles(languageFiles)
68
+ const parseProject = readAndParseProjectFile(config.file)
69
+ const parsePip = readAndParseLockFile(config.file)
30
70
 
31
- return { pipfileLock: parsePip, pipfilDependanceies: parseProject }
71
+ return { pipfileLock: parsePip, pipfilDependanceies: parseProject }
72
+ }
32
73
  } catch (err) {
33
74
  console.log(err.message.toString())
34
75
  process.exit(1)
@@ -44,6 +85,9 @@ const filePathForWindows = path => {
44
85
 
45
86
  module.exports = {
46
87
  getPythonDeps,
88
+ scaPythonParser,
89
+ readAndParseLockFile,
47
90
  readAndParseProjectFile,
48
- readAndParseLockFile
91
+ checkForCorrectFiles,
92
+ readLockFile
49
93
  }
@@ -1,9 +1,14 @@
1
1
  const { createPythonTSMessage } = require('../common/formatMessage')
2
- const { getPythonDeps } = require('./analysis')
2
+ const { getPythonDeps, secondaryParser } = require('./analysis')
3
3
 
4
4
  const pythonAnalysis = (config, languageFiles) => {
5
5
  const pythonDeps = getPythonDeps(config, languageFiles.PYTHON)
6
- return createPythonTSMessage(pythonDeps)
6
+
7
+ if (config.experimental) {
8
+ return pythonDeps
9
+ } else {
10
+ return createPythonTSMessage(pythonDeps)
11
+ }
7
12
  }
8
13
 
9
14
  module.exports = {
@@ -1,4 +1,5 @@
1
1
  const fs = require('fs')
2
+ const i18n = require('i18n')
2
3
 
3
4
  const readAndParseGemfile = file => {
4
5
  const gemFile = fs.readFileSync(file + '/Gemfile', 'utf8')
@@ -241,15 +242,25 @@ const buildSourceDependencyWithVersion = (
241
242
  return dependencies
242
243
  }
243
244
 
244
- const getRubyDeps = config => {
245
+ const getRubyDeps = (config, languageFiles) => {
245
246
  try {
247
+ checkForCorrectFiles(languageFiles)
246
248
  const parsedGem = readAndParseGemfile(config.file)
247
249
  const parsedLock = readAndParseGemLockFile(config.file)
248
250
 
249
251
  return { gemfilesDependanceies: parsedGem, gemfileLock: parsedLock }
250
252
  } catch (err) {
251
- console.log(err.message)
252
- process.exit(1)
253
+ throw err
254
+ }
255
+ }
256
+
257
+ const checkForCorrectFiles = languageFiles => {
258
+ if (!languageFiles.includes('Gemfile.lock')) {
259
+ throw new Error(i18n.__('languageAnalysisHasNoLockFile', 'ruby'))
260
+ }
261
+
262
+ if (!languageFiles.includes('Gemfile')) {
263
+ throw new Error(i18n.__('languageAnalysisProjectFileError', 'ruby'))
253
264
  }
254
265
  }
255
266
 
@@ -269,5 +280,6 @@ module.exports = {
269
280
  getVersion,
270
281
  getPatchLevel,
271
282
  formatSourceArr,
272
- getSourceArray
283
+ getSourceArray,
284
+ checkForCorrectFiles
273
285
  }
@@ -1,6 +1,7 @@
1
1
  const i18n = require('i18n')
2
2
  const fileFinder = require('./fileUtils')
3
3
  const rootFile = require('../audit/languageAnalysisEngine/getProjectRootFilenames')
4
+ const path = require('path')
4
5
 
5
6
  const autoDetectFileAndLanguage = async configToUse => {
6
7
  const entries = await fileFinder.findFile()
@@ -27,16 +28,10 @@ const autoDetectFileAndLanguage = async configToUse => {
27
28
  }
28
29
  }
29
30
 
30
- const autoDetectAuditFilesAndLanguages = async file => {
31
- const filePath = file
31
+ const autoDetectAuditFilesAndLanguages = async filePath => {
32
32
  let languagesFound = []
33
33
 
34
- if (filePath) {
35
- rootFile.getProjectRootFilenames(filePath)
36
- console.log(i18n.__('searchingAuditFileDirectory', filePath))
37
- } else {
38
- console.log(i18n.__('searchingAuditFileDirectory', process.cwd()))
39
- }
34
+ console.log(i18n.__('searchingAuditFileDirectory', filePath))
40
35
 
41
36
  await fileFinder.findFilesJava(languagesFound, filePath)
42
37
  await fileFinder.findFilesJavascript(languagesFound, filePath)
@@ -46,13 +41,11 @@ const autoDetectAuditFilesAndLanguages = async file => {
46
41
  await fileFinder.findFilesRuby(languagesFound, filePath)
47
42
  await fileFinder.findFilesDotNet(languagesFound, filePath)
48
43
 
49
- if (languagesFound.length <= 1) {
44
+ if (languagesFound) {
50
45
  return languagesFound
51
- } else {
52
- console.log(
53
- 'found multiple languages, please specify one using --file to run SCA audit'
54
- )
55
46
  }
47
+
48
+ return []
56
49
  }
57
50
 
58
51
  const hasWhiteSpace = s => {
@@ -62,12 +62,12 @@ export function formatScanOutput(scanResults: ScanResultsModel) {
62
62
  })
63
63
  let learnRow: string[] = []
64
64
  let adviceRow = []
65
+ const headerColour = chalk.hex(entry.colour)
65
66
  const headerRow = [
66
- chalk
67
- .hex(entry.colour)
68
- .bold(`CONTRAST-${count.toString().padStart(3, '0')}`),
69
- chalk.hex(entry.colour).bold('-'),
70
- chalk.hex(entry.colour).bold(`[${entry.severity}] ${entry.ruleId}`) +
67
+ headerColour(`CONTRAST-${count.toString().padStart(3, '0')}`),
68
+ headerColour(`-`),
69
+ headerColour(`[${entry.severity}] `) +
70
+ headerColour.bold(`${entry.ruleId}`) +
71
71
  entry.message
72
72
  ]
73
73
 
@@ -104,6 +104,8 @@ export function formatScanOutput(scanResults: ScanResultsModel) {
104
104
  })
105
105
  }
106
106
  printVulnInfo(projectOverview)
107
+
108
+ return projectOverview
107
109
  }
108
110
 
109
111
  function printVulnInfo(projectOverview: any) {
package/src/scan/help.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const commandLineUsage = require('command-line-usage')
2
2
  const i18n = require('i18n')
3
3
  const constants = require('../constants')
4
+ const { commonHelpLinks } = require('../common/commonHelp')
4
5
 
5
6
  const scanUsageGuide = commandLineUsage([
6
7
  {
@@ -35,9 +36,7 @@ const scanUsageGuide = commandLineUsage([
35
36
  'application-name'
36
37
  ]
37
38
  },
38
- {
39
- content: '{underline https://www.contrastsecurity.com}'
40
- }
39
+ commonHelpLinks()
41
40
  ])
42
41
 
43
42
  module.exports = {
@@ -28,7 +28,11 @@ const createProjectId = async (config, client) => {
28
28
  process.exit(1)
29
29
  return
30
30
  }
31
-
31
+ if (res.statusCode === 429) {
32
+ console.log(i18n.__('exceededFreeTier'))
33
+ process.exit(1)
34
+ return
35
+ }
32
36
  if (res.statusCode === 201) {
33
37
  console.log(i18n.__('projectCreatedScan'))
34
38
  if (config.verbose) {
package/src/scan/scan.ts CHANGED
@@ -47,6 +47,10 @@ export const sendScan = async (config: any) => {
47
47
  )
48
48
  console.log(i18n.__('genericServiceError', res.statusCode))
49
49
  }
50
+ if (res.statusCode === 429) {
51
+ console.log(i18n.__('exceededFreeTier'))
52
+ process.exit(1)
53
+ }
50
54
  if (res.statusCode === 403) {
51
55
  console.log(i18n.__('permissionsError'))
52
56
  process.exit(1)
@@ -1,13 +1,15 @@
1
1
  const paramHandler = require('../utils/paramsUtil/paramHandler')
2
- const constants = require('../../src/constants.js')
3
- const parsedCLIOptions = require('../../src/utils/parsedCLIOptions')
2
+ const constants = require('../constants.js')
4
3
  const path = require('path')
5
4
  const { supportedLanguagesScan } = require('../constants/constants')
6
5
  const i18n = require('i18n')
7
6
  const { scanUsageGuide } = require('./help')
7
+ const parsedCLIOptions = require('../utils/parsedCLIOptions')
8
8
 
9
- const getScanConfig = argv => {
10
- let scanParams = parsedCLIOptions.getCommandLineArgsCustom(
9
+ const getScanConfig = async (contrastConf, command, argv) => {
10
+ let scanParams = await parsedCLIOptions.getCommandLineArgsCustom(
11
+ contrastConf,
12
+ command,
11
13
  argv,
12
14
  constants.commandLineDefinitions.scanOptionDefinitions
13
15
  )
@@ -4,11 +4,15 @@ const oraFunctions = require('../utils/oraWrapper')
4
4
  const _ = require('lodash')
5
5
  const i18n = require('i18n')
6
6
  const oraWrapper = require('../utils/oraWrapper')
7
+ const readLine = require('readline')
7
8
 
8
9
  const getScanId = async (config, codeArtifactId, client) => {
9
10
  return client
10
11
  .getScanId(config, codeArtifactId)
11
12
  .then(res => {
13
+ if (res.statusCode == 429) {
14
+ throw new Error(i18n.__('exceededFreeTier'))
15
+ }
12
16
  return res.body.id
13
17
  })
14
18
  .catch(err => {
@@ -88,13 +92,57 @@ const returnScanResults = async (
88
92
  startScanSpinner,
89
93
  'Contrast Scan timed out at the specified ' + timeout + ' seconds.'
90
94
  )
91
- console.log('Please try again, allowing more time.')
92
- process.exit(1)
95
+
96
+ const isCI = process.env.CONTRAST_CODESEC_CI
97
+ ? JSON.parse(process.env.CONTRAST_CODESEC_CI)
98
+ : false
99
+ if (!isCI) {
100
+ const retry = await retryScanPrompt()
101
+ timeout = retry.timeout
102
+ } else {
103
+ console.log('Please try again, allowing more time')
104
+ process.exit(1)
105
+ }
93
106
  }
94
107
  }
95
108
  }
96
109
  }
97
110
 
111
+ const retryScanPrompt = async () => {
112
+ const rl = readLine.createInterface({
113
+ input: process.stdin,
114
+ output: process.stdout
115
+ })
116
+
117
+ return new Promise((resolve, reject) => {
118
+ requestUtils.timeOutError(30000, reject)
119
+
120
+ rl.question(
121
+ '🔁 Do you want to continue waiting on Scan? [Y/N]\n',
122
+ async input => {
123
+ if (input.toLowerCase() === 'yes' || input.toLowerCase() === 'y') {
124
+ console.log('Continuing wait for Scan')
125
+ rl.close()
126
+ resolve({ timeout: 300 })
127
+ } else if (
128
+ input.toLowerCase() === 'no' ||
129
+ input.toLowerCase() === 'n'
130
+ ) {
131
+ rl.close()
132
+ console.log('Contrast Scan Retry Cancelled: Exiting')
133
+ resolve(process.exit(1))
134
+ } else {
135
+ rl.close()
136
+ console.log('Invalid Input: Exiting')
137
+ resolve(process.exit(1))
138
+ }
139
+ }
140
+ )
141
+ }).catch(e => {
142
+ throw e
143
+ })
144
+ }
145
+
98
146
  const returnScanResultsInstances = async (config, scanId) => {
99
147
  const client = commonApi.getHttpClient(config)
100
148
  let result
@@ -118,5 +166,6 @@ module.exports = {
118
166
  getScanId: getScanId,
119
167
  returnScanResults: returnScanResults,
120
168
  pollScanResults: pollScanResults,
121
- returnScanResultsInstances: returnScanResultsInstances
169
+ returnScanResultsInstances: returnScanResultsInstances,
170
+ retryScanPrompt
122
171
  }