@contrast/contrast 1.0.10 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +1 -1
  2. package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +39 -28
  3. package/dist/audit/languageAnalysisEngine/report/models/reportGuidanceModel.js +6 -0
  4. package/dist/audit/languageAnalysisEngine/report/models/reportOutputModel.js +1 -2
  5. package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +1 -0
  6. package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +11 -7
  7. package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +1 -2
  8. package/dist/commands/audit/auditConfig.js +3 -3
  9. package/dist/commands/audit/processAudit.js +4 -2
  10. package/dist/commands/auth/auth.js +1 -1
  11. package/dist/commands/config/config.js +2 -2
  12. package/dist/commands/scan/processScan.js +11 -4
  13. package/dist/commands/scan/sca/scaAnalysis.js +10 -3
  14. package/dist/common/HTTPClient.js +9 -0
  15. package/dist/common/fail.js +66 -0
  16. package/dist/common/versionChecker.js +1 -1
  17. package/dist/constants/constants.js +1 -1
  18. package/dist/constants/locales.js +6 -3
  19. package/dist/constants.js +39 -1
  20. package/dist/index.js +5 -2
  21. package/dist/scaAnalysis/common/scaParserForGoAndJava.js +32 -0
  22. package/dist/scaAnalysis/common/treeUpload.js +20 -5
  23. package/dist/scaAnalysis/dotnet/analysis.js +15 -3
  24. package/dist/scaAnalysis/go/goAnalysis.js +8 -2
  25. package/dist/scaAnalysis/java/analysis.js +10 -6
  26. package/dist/scaAnalysis/java/index.js +7 -1
  27. package/dist/scaAnalysis/java/javaBuildDepsParser.js +19 -3
  28. package/dist/scaAnalysis/python/analysis.js +43 -5
  29. package/dist/scaAnalysis/python/index.js +7 -2
  30. package/dist/scaAnalysis/ruby/analysis.js +14 -4
  31. package/dist/scan/formatScanOutput.js +6 -5
  32. package/dist/scan/populateProjectIdAndProjectName.js +5 -0
  33. package/dist/scan/scan.js +4 -0
  34. package/dist/scan/scanConfig.js +3 -3
  35. package/dist/scan/scanResults.js +39 -3
  36. package/dist/telemetry/telemetry.js +137 -0
  37. package/dist/utils/getConfig.js +2 -2
  38. package/dist/utils/parsedCLIOptions.js +3 -1
  39. package/dist/utils/requestUtils.js +7 -1
  40. package/package.json +1 -1
  41. package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +57 -39
  42. package/src/audit/languageAnalysisEngine/report/models/reportGuidanceModel.ts +5 -0
  43. package/src/audit/languageAnalysisEngine/report/models/reportOutputModel.ts +1 -7
  44. package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +2 -0
  45. package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +15 -8
  46. package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +2 -2
  47. package/src/commands/audit/auditConfig.ts +10 -3
  48. package/src/commands/audit/processAudit.ts +16 -2
  49. package/src/commands/auth/auth.js +3 -1
  50. package/src/commands/config/config.js +4 -2
  51. package/src/commands/scan/processScan.js +18 -4
  52. package/src/commands/scan/sca/scaAnalysis.js +11 -3
  53. package/src/common/HTTPClient.js +14 -0
  54. package/src/common/fail.js +75 -0
  55. package/src/common/versionChecker.ts +1 -1
  56. package/src/constants/constants.js +1 -1
  57. package/src/constants/locales.js +8 -4
  58. package/src/constants.js +43 -1
  59. package/src/index.ts +17 -2
  60. package/src/scaAnalysis/common/scaParserForGoAndJava.js +41 -0
  61. package/src/scaAnalysis/common/treeUpload.js +21 -6
  62. package/src/scaAnalysis/dotnet/analysis.js +21 -3
  63. package/src/scaAnalysis/go/goAnalysis.js +9 -2
  64. package/src/scaAnalysis/java/analysis.js +11 -6
  65. package/src/scaAnalysis/java/index.js +9 -1
  66. package/src/scaAnalysis/java/javaBuildDepsParser.js +25 -6
  67. package/src/scaAnalysis/python/analysis.js +49 -5
  68. package/src/scaAnalysis/python/index.js +7 -2
  69. package/src/scaAnalysis/ruby/analysis.js +16 -4
  70. package/src/scan/formatScanOutput.ts +7 -5
  71. package/src/scan/populateProjectIdAndProjectName.js +5 -1
  72. package/src/scan/scan.ts +4 -0
  73. package/src/scan/scanConfig.js +5 -3
  74. package/src/scan/scanResults.js +46 -3
  75. package/src/telemetry/telemetry.ts +154 -0
  76. package/src/utils/getConfig.ts +4 -6
  77. package/src/utils/parsedCLIOptions.js +14 -1
  78. package/src/utils/requestUtils.js +8 -1
@@ -2,11 +2,14 @@
2
2
  const commonApi = require('../../utils/commonApi');
3
3
  const { APP_VERSION } = require('../../constants/constants');
4
4
  const commonSendSnapShot = async (analysis, config) => {
5
- const requestBody = {
6
- appID: config.applicationId,
7
- cliVersion: APP_VERSION,
8
- snapshot: analysis
9
- };
5
+ let requestBody = {};
6
+ config.experimental === true
7
+ ? (requestBody = sendToSCAServices(config, analysis))
8
+ : (requestBody = {
9
+ appID: config.applicationId,
10
+ cliVersion: APP_VERSION,
11
+ snapshot: analysis
12
+ });
10
13
  const client = commonApi.getHttpClient(config);
11
14
  return client
12
15
  .sendSnapshot(requestBody, config)
@@ -22,6 +25,18 @@ const commonSendSnapShot = async (analysis, config) => {
22
25
  throw err;
23
26
  });
24
27
  };
28
+ const sendToSCAServices = (config, analysis) => {
29
+ return {
30
+ applicationId: config.applicationId,
31
+ dependencyTree: analysis,
32
+ organizationId: config.organizationId,
33
+ language: config.language,
34
+ tool: {
35
+ name: 'Contrast Codesec',
36
+ version: APP_VERSION
37
+ }
38
+ };
39
+ };
25
40
  module.exports = {
26
41
  commonSendSnapShot
27
42
  };
@@ -31,13 +31,25 @@ const readAndParseLockFile = lockFilePath => {
31
31
  }
32
32
  return lockFile;
33
33
  };
34
+ const checkForCorrectFiles = languageFiles => {
35
+ if (!languageFiles.includes('packages.lock.json')) {
36
+ throw new Error(i18n.__('languageAnalysisHasNoLockFile', '.NET'));
37
+ }
38
+ if (!languageFiles.some(i => i.includes('.csproj'))) {
39
+ throw new Error(i18n.__('languageAnalysisProjectFileError', '.NET'));
40
+ }
41
+ };
34
42
  const getDotNetDeps = (filePath, languageFiles) => {
35
- const projectFile = readAndParseProjectFile(filePath + `/${languageFiles[0]}`);
36
- const lockFile = readAndParseLockFile(filePath + `/${languageFiles[1]}`);
43
+ checkForCorrectFiles(languageFiles);
44
+ const projectFileName = languageFiles.find(fileName => fileName.includes('.csproj'));
45
+ const lockFileName = languageFiles.find(fileName => fileName.includes('.json'));
46
+ const projectFile = readAndParseProjectFile(filePath + `/${projectFileName}`);
47
+ const lockFile = readAndParseLockFile(filePath + `/${lockFileName}`);
37
48
  return { projectFile, lockFile };
38
49
  };
39
50
  module.exports = {
40
51
  getDotNetDeps,
41
52
  readAndParseProjectFile,
42
- readAndParseLockFile
53
+ readAndParseLockFile,
54
+ checkForCorrectFiles
43
55
  };
@@ -1,12 +1,18 @@
1
1
  "use strict";
2
2
  const { createGoTSMessage } = require('../common/formatMessage');
3
+ const { parseDependenciesForSCAServices } = require('../common/scaParserForGoAndJava');
3
4
  const goReadDepFile = require('./goReadDepFile');
4
5
  const goParseDeps = require('./goParseDeps');
5
- const goAnalysis = (config, languageFiles) => {
6
+ const goAnalysis = config => {
6
7
  try {
7
8
  const rawGoDependencies = goReadDepFile.getGoDependencies(config);
8
9
  const parsedGoDependencies = goParseDeps.parseGoDependencies(rawGoDependencies);
9
- return createGoTSMessage(parsedGoDependencies);
10
+ if (config.experimental) {
11
+ return parseDependenciesForSCAServices(parsedGoDependencies);
12
+ }
13
+ else {
14
+ return createGoTSMessage(parsedGoDependencies);
15
+ }
10
16
  }
11
17
  catch (e) {
12
18
  console.log(e.message.toString());
@@ -5,17 +5,20 @@ const i18n = require('i18n');
5
5
  const fs = require('fs');
6
6
  const MAVEN = 'maven';
7
7
  const GRADLE = 'gradle';
8
- const determineProjectTypeAndCwd = (files, file) => {
8
+ const determineProjectTypeAndCwd = (files, config) => {
9
9
  const projectData = {};
10
+ if (files.length > 1) {
11
+ files = files.filter(i => config.fileName.includes(i));
12
+ }
10
13
  if (files[0].includes('pom.xml')) {
11
14
  projectData.projectType = MAVEN;
12
15
  }
13
16
  else if (files[0].includes('build.gradle')) {
14
17
  projectData.projectType = GRADLE;
15
18
  }
16
- projectData.cwd = file
17
- ? file.replace('pom.xml', '').replace('build.gradle', '')
18
- : file;
19
+ projectData.cwd = config.file
20
+ ? config.file.replace('pom.xml', '').replace('build.gradle', '')
21
+ : config.file;
19
22
  return projectData;
20
23
  };
21
24
  const buildMaven = (config, projectData, timeout) => {
@@ -86,7 +89,7 @@ const getJavaBuildDeps = (config, files) => {
86
89
  projectType: undefined
87
90
  };
88
91
  try {
89
- const projectData = determineProjectTypeAndCwd(files, config.file);
92
+ const projectData = determineProjectTypeAndCwd(files, config);
90
93
  if (projectData.projectType === MAVEN) {
91
94
  output.mvnDependancyTreeOutput = buildMaven(config, projectData, timeout);
92
95
  }
@@ -101,5 +104,6 @@ const getJavaBuildDeps = (config, files) => {
101
104
  }
102
105
  };
103
106
  module.exports = {
104
- getJavaBuildDeps
107
+ getJavaBuildDeps,
108
+ determineProjectTypeAndCwd
105
109
  };
@@ -2,12 +2,18 @@
2
2
  const analysis = require('./analysis');
3
3
  const { parseBuildDeps } = require('./javaBuildDepsParser');
4
4
  const { createJavaTSMessage } = require('../common/formatMessage');
5
+ const { parseDependenciesForSCAServices } = require('../common/scaParserForGoAndJava');
5
6
  const javaAnalysis = (config, languageFiles) => {
6
7
  languageFiles.JAVA.forEach(file => {
7
8
  file.replace('build.gradle.kts', 'build.gradle');
8
9
  });
9
10
  const javaDeps = buildJavaTree(config, languageFiles.JAVA);
10
- return createJavaTSMessage(javaDeps);
11
+ if (config.experimental) {
12
+ return parseDependenciesForSCAServices(javaDeps);
13
+ }
14
+ else {
15
+ return createJavaTSMessage(javaDeps);
16
+ }
11
17
  };
12
18
  const buildJavaTree = (config, files) => {
13
19
  const javaBuildDeps = analysis.getJavaBuildDeps(config, files);
@@ -14,13 +14,12 @@ 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]);
17
18
  obj.push(shavedOutput[dep]
18
19
  .replace('+-', '+---')
19
20
  .replace('[INFO]', '')
20
21
  .replace('\\-', '\\---')
21
22
  .replace(':jar:', ':')
22
- .replace(':test', '')
23
- .replace(':compile', '')
24
23
  .replace(' +', '+')
25
24
  .replace(' |', '|')
26
25
  .replace(' \\', '\\')
@@ -50,6 +49,21 @@ const preParser = shavedOutput => {
50
49
  }
51
50
  return depTree;
52
51
  };
52
+ const shaveDependencyType = dep => {
53
+ if (dep.endsWith('\r')) {
54
+ dep = dep.slice(0, -1);
55
+ }
56
+ if (dep.endsWith(':test')) {
57
+ dep = dep.slice(0, -5);
58
+ }
59
+ if (dep.endsWith(':compile')) {
60
+ dep = dep.slice(0, -8);
61
+ }
62
+ if (dep.endsWith(':provided')) {
63
+ dep = dep.slice(0, -9);
64
+ }
65
+ return dep;
66
+ };
53
67
  const shaveOutput = (gradleDependencyTreeOutput, projectType) => {
54
68
  let shavedOutput = gradleDependencyTreeOutput.split('\n');
55
69
  if (projectType === 'maven') {
@@ -335,5 +349,7 @@ module.exports = {
335
349
  computeRelationToLastElement,
336
350
  addIndentation,
337
351
  computeLevel,
338
- computeIndentation
352
+ computeIndentation,
353
+ shaveDependencyType,
354
+ preParser
339
355
  };
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  const multiReplace = require('string-multiple-replace');
3
3
  const fs = require('fs');
4
+ const i18n = require('i18n');
4
5
  const readAndParseProjectFile = file => {
5
6
  const filePath = filePathForWindows(file + '/Pipfile');
6
7
  const pipFile = fs.readFileSync(filePath, 'utf8');
@@ -18,11 +19,45 @@ const readAndParseLockFile = file => {
18
19
  delete parsedPipLock['default'];
19
20
  return parsedPipLock;
20
21
  };
21
- const getPythonDeps = config => {
22
+ const readLockFile = file => {
23
+ const filePath = filePathForWindows(file + '/Pipfile.lock');
24
+ const lockFile = fs.readFileSync(filePath, 'utf8');
25
+ let parsedPipLock = JSON.parse(lockFile);
26
+ return parsedPipLock['default'];
27
+ };
28
+ const scaPythonParser = pythonDependencies => {
29
+ let pythonParsedDeps = {};
30
+ for (let key in pythonDependencies) {
31
+ pythonParsedDeps[key] = {};
32
+ pythonParsedDeps[key].version = pythonDependencies[key].version.replace('==', '');
33
+ pythonParsedDeps[key].group = null;
34
+ pythonParsedDeps[key].name = key;
35
+ pythonParsedDeps[key].isProduction = true;
36
+ pythonParsedDeps[key].dependencies = [];
37
+ pythonParsedDeps[key].directDependency = true;
38
+ }
39
+ return pythonParsedDeps;
40
+ };
41
+ const checkForCorrectFiles = languageFiles => {
42
+ if (!languageFiles.includes('Pipfile.lock')) {
43
+ throw new Error(i18n.__('languageAnalysisHasNoLockFile', 'python'));
44
+ }
45
+ if (!languageFiles.includes('Pipfile')) {
46
+ throw new Error(i18n.__('languageAnalysisProjectFileError', 'python'));
47
+ }
48
+ };
49
+ const getPythonDeps = (config, languageFiles) => {
22
50
  try {
23
- const parseProject = readAndParseProjectFile(config.file);
24
- const parsePip = readAndParseLockFile(config.file);
25
- return { pipfileLock: parsePip, pipfilDependanceies: parseProject };
51
+ if (config.experimental) {
52
+ let pythonLockFileContents = readLockFile(config.file);
53
+ return scaPythonParser(pythonLockFileContents);
54
+ }
55
+ else {
56
+ checkForCorrectFiles(languageFiles);
57
+ const parseProject = readAndParseProjectFile(config.file);
58
+ const parsePip = readAndParseLockFile(config.file);
59
+ return { pipfileLock: parsePip, pipfilDependanceies: parseProject };
60
+ }
26
61
  }
27
62
  catch (err) {
28
63
  console.log(err.message.toString());
@@ -37,6 +72,9 @@ const filePathForWindows = path => {
37
72
  };
38
73
  module.exports = {
39
74
  getPythonDeps,
75
+ scaPythonParser,
76
+ readAndParseLockFile,
40
77
  readAndParseProjectFile,
41
- readAndParseLockFile
78
+ checkForCorrectFiles,
79
+ readLockFile
42
80
  };
@@ -1,9 +1,14 @@
1
1
  "use strict";
2
2
  const { createPythonTSMessage } = require('../common/formatMessage');
3
- const { getPythonDeps } = require('./analysis');
3
+ const { getPythonDeps, secondaryParser } = require('./analysis');
4
4
  const pythonAnalysis = (config, languageFiles) => {
5
5
  const pythonDeps = getPythonDeps(config, languageFiles.PYTHON);
6
- return createPythonTSMessage(pythonDeps);
6
+ if (config.experimental) {
7
+ return pythonDeps;
8
+ }
9
+ else {
10
+ return createPythonTSMessage(pythonDeps);
11
+ }
7
12
  };
8
13
  module.exports = {
9
14
  pythonAnalysis
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  const fs = require('fs');
3
+ const i18n = require('i18n');
3
4
  const readAndParseGemfile = file => {
4
5
  const gemFile = fs.readFileSync(file + '/Gemfile', 'utf8');
5
6
  const rubyArray = gemFile.split('\n');
@@ -188,15 +189,23 @@ const buildSourceDependencyWithVersion = (whitespaceRegx, dependencyRegEx, line,
188
189
  }
189
190
  return dependencies;
190
191
  };
191
- const getRubyDeps = config => {
192
+ const getRubyDeps = (config, languageFiles) => {
192
193
  try {
194
+ checkForCorrectFiles(languageFiles);
193
195
  const parsedGem = readAndParseGemfile(config.file);
194
196
  const parsedLock = readAndParseGemLockFile(config.file);
195
197
  return { gemfilesDependanceies: parsedGem, gemfileLock: parsedLock };
196
198
  }
197
199
  catch (err) {
198
- console.log(err.message);
199
- process.exit(1);
200
+ throw err;
201
+ }
202
+ };
203
+ const checkForCorrectFiles = languageFiles => {
204
+ if (!languageFiles.includes('Gemfile.lock')) {
205
+ throw new Error(i18n.__('languageAnalysisHasNoLockFile', 'ruby'));
206
+ }
207
+ if (!languageFiles.includes('Gemfile')) {
208
+ throw new Error(i18n.__('languageAnalysisProjectFileError', 'ruby'));
200
209
  }
201
210
  };
202
211
  const trimWhiteSpace = string => {
@@ -214,5 +223,6 @@ module.exports = {
214
223
  getVersion,
215
224
  getPatchLevel,
216
225
  formatSourceArr,
217
- getSourceArray
226
+ getSourceArray,
227
+ checkForCorrectFiles
218
228
  };
@@ -53,12 +53,12 @@ function formatScanOutput(scanResults) {
53
53
  });
54
54
  let learnRow = [];
55
55
  let adviceRow = [];
56
+ const headerColour = chalk_1.default.hex(entry.colour);
56
57
  const headerRow = [
57
- chalk_1.default
58
- .hex(entry.colour)
59
- .bold(`CONTRAST-${count.toString().padStart(3, '0')}`),
60
- chalk_1.default.hex(entry.colour).bold('-'),
61
- chalk_1.default.hex(entry.colour).bold(`[${entry.severity}] ${entry.ruleId}`) +
58
+ headerColour(`CONTRAST-${count.toString().padStart(3, '0')}`),
59
+ headerColour(`-`),
60
+ headerColour(`[${entry.severity}] `) +
61
+ headerColour.bold(`${entry.ruleId}`) +
62
62
  entry.message
63
63
  ];
64
64
  const codePath = entry.codePath?.replace(/^@/, '');
@@ -90,6 +90,7 @@ function formatScanOutput(scanResults) {
90
90
  });
91
91
  }
92
92
  printVulnInfo(projectOverview);
93
+ return projectOverview;
93
94
  }
94
95
  exports.formatScanOutput = formatScanOutput;
95
96
  function printVulnInfo(projectOverview) {
@@ -25,6 +25,11 @@ const createProjectId = async (config, client) => {
25
25
  process.exit(1);
26
26
  return;
27
27
  }
28
+ if (res.statusCode === 429) {
29
+ console.log(i18n.__('exceededFreeTier'));
30
+ process.exit(1);
31
+ return;
32
+ }
28
33
  if (res.statusCode === 201) {
29
34
  console.log(i18n.__('projectCreatedScan'));
30
35
  if (config.verbose) {
package/dist/scan/scan.js CHANGED
@@ -45,6 +45,10 @@ const sendScan = async (config) => {
45
45
  oraWrapper_1.default.failSpinner(startUploadSpinner, i18n_1.default.__('uploadingScanFail'));
46
46
  console.log(i18n_1.default.__('genericServiceError', res.statusCode));
47
47
  }
48
+ if (res.statusCode === 429) {
49
+ console.log(i18n_1.default.__('exceededFreeTier'));
50
+ process.exit(1);
51
+ }
48
52
  if (res.statusCode === 403) {
49
53
  console.log(i18n_1.default.__('permissionsError'));
50
54
  process.exit(1);
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  const paramHandler = require('../utils/paramsUtil/paramHandler');
3
3
  const constants = require('../../src/constants.js');
4
- const parsedCLIOptions = require('../../src/utils/parsedCLIOptions');
5
4
  const path = require('path');
6
5
  const { supportedLanguagesScan } = require('../constants/constants');
7
6
  const i18n = require('i18n');
8
7
  const { scanUsageGuide } = require('./help');
9
- const getScanConfig = argv => {
10
- let scanParams = parsedCLIOptions.getCommandLineArgsCustom(argv, constants.commandLineDefinitions.scanOptionDefinitions);
8
+ const parsedCLIOptions = require('../utils/parsedCLIOptions');
9
+ const getScanConfig = async (contrastConf, command, argv) => {
10
+ let scanParams = await parsedCLIOptions.getCommandLineArgsCustom(contrastConf, command, argv, constants.commandLineDefinitions.scanOptionDefinitions);
11
11
  if (scanParams.help) {
12
12
  printHelpMessage();
13
13
  process.exit(0);
@@ -5,10 +5,14 @@ const oraFunctions = require('../utils/oraWrapper');
5
5
  const _ = require('lodash');
6
6
  const i18n = require('i18n');
7
7
  const oraWrapper = require('../utils/oraWrapper');
8
+ const readLine = require('readline');
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 => {
@@ -61,12 +65,43 @@ const returnScanResults = async (config, codeArtifactId, newProject, timeout, st
61
65
  let endTime = new Date() - startTime;
62
66
  if (requestUtils.millisToSeconds(endTime) > timeout) {
63
67
  oraFunctions.failSpinner(startScanSpinner, 'Contrast Scan timed out at the specified ' + timeout + ' seconds.');
64
- console.log('Please try again, allowing more time.');
65
- process.exit(1);
68
+ if (!config.isCI) {
69
+ const retry = await retryScanPrompt();
70
+ timeout = retry.timeout;
71
+ }
66
72
  }
67
73
  }
68
74
  }
69
75
  };
76
+ const retryScanPrompt = async () => {
77
+ const rl = readLine.createInterface({
78
+ input: process.stdin,
79
+ output: process.stdout
80
+ });
81
+ return new Promise((resolve, reject) => {
82
+ requestUtils.timeOutError(30000, reject);
83
+ rl.question('🔁 Do you want to continue waiting on Scan? [Y/N]\n', async (input) => {
84
+ if (input.toLowerCase() === 'yes' || input.toLowerCase() === 'y') {
85
+ console.log('Continuing wait for Scan');
86
+ rl.close();
87
+ resolve({ timeout: 300 });
88
+ }
89
+ else if (input.toLowerCase() === 'no' ||
90
+ input.toLowerCase() === 'n') {
91
+ rl.close();
92
+ console.log('Contrast Scan Retry Cancelled: Exiting');
93
+ resolve(process.exit(1));
94
+ }
95
+ else {
96
+ rl.close();
97
+ console.log('Invalid Input: Exiting');
98
+ resolve(process.exit(1));
99
+ }
100
+ });
101
+ }).catch(e => {
102
+ throw e;
103
+ });
104
+ };
70
105
  const returnScanResultsInstances = async (config, scanId) => {
71
106
  const client = commonApi.getHttpClient(config);
72
107
  let result;
@@ -89,5 +124,6 @@ module.exports = {
89
124
  getScanId: getScanId,
90
125
  returnScanResults: returnScanResults,
91
126
  pollScanResults: pollScanResults,
92
- returnScanResultsInstances: returnScanResultsInstances
127
+ returnScanResultsInstances: returnScanResultsInstances,
128
+ retryScanPrompt
93
129
  };
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.sha1Base64Value = exports.findParamValueFromArgs = exports.paramExists = exports.obfuscateParams = exports.sendTelemetryRequest = exports.sendTelemetryConfigAsObject = exports.sendTelemetryConfigAsConfObj = exports.TELEMETRY_CLI_TIME_TO_AUTH_EVENT = exports.TELEMETRY_CLI_COMMANDS_EVENT = void 0;
27
+ const commonApi_1 = require("../utils/commonApi");
28
+ const crypto = __importStar(require("crypto"));
29
+ exports.TELEMETRY_CLI_COMMANDS_EVENT = 'CLI_COMMANDS';
30
+ exports.TELEMETRY_CLI_TIME_TO_AUTH_EVENT = 'CLI_TIME_TO_AUTH';
31
+ const sendTelemetryConfigAsConfObj = async (config, command, argv, result, language) => {
32
+ const hostParam = '--host';
33
+ const hostParamAlias = '-h';
34
+ const orgIdParam = '--organization-id';
35
+ const orgIdParamAlias = '-o';
36
+ const authParam = '--authorization';
37
+ const apiKeyParam = '--api-key';
38
+ let configToUse;
39
+ if ((0, exports.paramExists)(argv, hostParam, hostParamAlias) &&
40
+ (0, exports.paramExists)(argv, orgIdParam, orgIdParamAlias) &&
41
+ (0, exports.paramExists)(argv, authParam, null) &&
42
+ (0, exports.paramExists)(argv, apiKeyParam, null)) {
43
+ configToUse = {
44
+ host: (0, exports.findParamValueFromArgs)(argv, hostParam, hostParamAlias),
45
+ organizationId: (0, exports.findParamValueFromArgs)(argv, orgIdParam, orgIdParamAlias),
46
+ authorization: (0, exports.findParamValueFromArgs)(argv, authParam, null),
47
+ apiKey: (0, exports.findParamValueFromArgs)(argv, apiKeyParam, null)
48
+ };
49
+ }
50
+ else if (config &&
51
+ config.get('host') &&
52
+ config.get('organizationId') &&
53
+ config.get('authorization') &&
54
+ config.get('apiKey')) {
55
+ configToUse = {
56
+ host: config.get('host')?.slice(0, -1),
57
+ organizationId: config.get('organizationId'),
58
+ authorization: config.get('authorization'),
59
+ apiKey: config.get('apiKey')
60
+ };
61
+ }
62
+ else {
63
+ return;
64
+ }
65
+ return await (0, exports.sendTelemetryConfigAsObject)(configToUse, command, argv, result, language);
66
+ };
67
+ exports.sendTelemetryConfigAsConfObj = sendTelemetryConfigAsConfObj;
68
+ const sendTelemetryConfigAsObject = async (config, command, argv, result, language) => {
69
+ const obfuscatedParams = (0, exports.obfuscateParams)(argv);
70
+ const requestBody = {
71
+ event: exports.TELEMETRY_CLI_COMMANDS_EVENT,
72
+ details: {
73
+ ip_address: '',
74
+ account_name: '',
75
+ account_host: '',
76
+ company_domain: '',
77
+ command: `contrast ${command} ${obfuscatedParams}`,
78
+ app_id: config && config.applicationId
79
+ ? (0, exports.sha1Base64Value)(config.applicationId)
80
+ : 'undefined',
81
+ project_id: config && config.projectId
82
+ ? (0, exports.sha1Base64Value)(config.projectId)
83
+ : 'undefined',
84
+ language: language,
85
+ result: result,
86
+ additional_info: '',
87
+ timestamp: new Date().toUTCString()
88
+ }
89
+ };
90
+ return await (0, exports.sendTelemetryRequest)(config, requestBody);
91
+ };
92
+ exports.sendTelemetryConfigAsObject = sendTelemetryConfigAsObject;
93
+ const sendTelemetryRequest = async (config, requestBody) => {
94
+ const client = (0, commonApi_1.getHttpClient)(config);
95
+ return client
96
+ .postTelemetry(config, requestBody)
97
+ .then((res) => {
98
+ if (res.statusCode !== 200 && config.debug === true) {
99
+ console.log('Telemetry failed to send with status', res.statusCode);
100
+ }
101
+ return { statusCode: res.statusCode, statusMessage: res.statusMessage };
102
+ })
103
+ .catch((err) => {
104
+ return;
105
+ });
106
+ };
107
+ exports.sendTelemetryRequest = sendTelemetryRequest;
108
+ const obfuscateParams = (argv) => {
109
+ return argv
110
+ .join(' ')
111
+ .replace(/--(authorization [A-Z0-9]+)/gi, '--authorization *****')
112
+ .replace(/-(o [A-Z0-9-]+)/gi, '-o *****')
113
+ .replace(/--(organization-id [A-Z0-9-]+)/gi, '--organization-id *****')
114
+ .replace(/--(api-key [A-Z0-9]+)/gi, '--api-key *****');
115
+ };
116
+ exports.obfuscateParams = obfuscateParams;
117
+ const paramExists = (argv, param, paramAlias) => {
118
+ return argv.find((arg) => arg === param || arg === paramAlias);
119
+ };
120
+ exports.paramExists = paramExists;
121
+ const findParamValueFromArgs = (argv, param, paramAlias) => {
122
+ let paramAsValue;
123
+ argv.forEach((arg, index) => {
124
+ if (arg === param ||
125
+ (arg === paramAlias &&
126
+ argv[index + 1] !== undefined &&
127
+ argv[index + 1] !== null)) {
128
+ paramAsValue = argv[index + 1];
129
+ }
130
+ });
131
+ return paramAsValue;
132
+ };
133
+ exports.findParamValueFromArgs = findParamValueFromArgs;
134
+ const sha1Base64Value = (value) => {
135
+ return crypto.createHash('sha1').update(value).digest('base64');
136
+ };
137
+ exports.sha1Base64Value = sha1Base64Value;
@@ -10,8 +10,8 @@ const localConfig = (name, version) => {
10
10
  configName: name
11
11
  });
12
12
  config.set('version', version);
13
- if (process.env.CONTRAST_CODSEC_DISABLE_UPDATE_MESSAGE) {
14
- config.set('updateMessageHidden', JSON.parse(process.env.CONTRAST_CODSEC_DISABLE_UPDATE_MESSAGE.toLowerCase()));
13
+ if (process.env.CONTRAST_CODSEC_CI) {
14
+ config.set('isCI', JSON.parse(process.env.CONTRAST_CODSEC_CI.toLowerCase()));
15
15
  }
16
16
  if (!config.has('host')) {
17
17
  config.set('host', 'https://ce.contrastsecurity.com/');
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  const commandLineArgs = require('command-line-args');
3
- const getCommandLineArgsCustom = (parameterList, optionDefinitions) => {
3
+ const { sendTelemetryConfigAsConfObj } = require('../telemetry/telemetry');
4
+ const getCommandLineArgsCustom = async (contrastConf, command, parameterList, optionDefinitions) => {
4
5
  try {
5
6
  return commandLineArgs(optionDefinitions, {
6
7
  argv: parameterList,
@@ -10,6 +11,7 @@ const getCommandLineArgsCustom = (parameterList, optionDefinitions) => {
10
11
  });
11
12
  }
12
13
  catch (e) {
14
+ await sendTelemetryConfigAsConfObj(contrastConf, command, parameterList, 'FAILURE', 'undefined');
13
15
  console.log(e.message.toString());
14
16
  process.exit(1);
15
17
  }
@@ -11,8 +11,14 @@ const millisToSeconds = millis => {
11
11
  const sleep = ms => {
12
12
  return new Promise(resolve => setTimeout(resolve, ms));
13
13
  };
14
+ const timeOutError = (ms, reject) => {
15
+ return setTimeout(() => {
16
+ reject(new Error(`No input detected after 30s`));
17
+ }, ms);
18
+ };
14
19
  module.exports = {
15
20
  sendRequest: sendRequest,
16
21
  sleep: sleep,
17
- millisToSeconds: millisToSeconds
22
+ millisToSeconds: millisToSeconds,
23
+ timeOutError: timeOutError
18
24
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/contrast",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "description": "Contrast Security's command line tool",
5
5
  "main": "dist/index.js",
6
6
  "bin": {