@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
package/.prettierignore CHANGED
@@ -1,7 +1 @@
1
- test/commands/**
2
1
  dist/**
3
- test/errorHandling.spec.ts
4
- **/models
5
- **/audit/autodetection/autoDetectLanguage.ts
6
- **/commands/audit/auditConfig.ts
7
- **/audit/languageAnalysisEngine/report
@@ -142,10 +142,12 @@ const parseMvn = mvnDependancyTreeOutput => {
142
142
  });
143
143
  return parsedDepObj;
144
144
  };
145
- exports.shaveConsoleOutputUntilItFindsFirsDigraphMention = shaveConsoleOutputUntilItFindsFirsDigraphMention;
145
+ exports.shaveConsoleOutputUntilItFindsFirsDigraphMention =
146
+ shaveConsoleOutputUntilItFindsFirsDigraphMention;
146
147
  exports.getDigraphObjInfo = getDigraphObjInfo;
147
148
  exports.createDigraphObjKey = createDigraphObjKey;
148
- exports.turnDigraphDependanciesIntoArrOfInnerDep = turnDigraphDependanciesIntoArrOfInnerDep;
149
+ exports.turnDigraphDependanciesIntoArrOfInnerDep =
150
+ turnDigraphDependanciesIntoArrOfInnerDep;
149
151
  exports.hasVersion = hasVersion;
150
152
  exports.formatKeyName = formatKeyName;
151
153
  exports.createOuterDependanciesAndType = createOuterDependanciesAndType;
@@ -21,4 +21,5 @@ const checkForMultipleIdentifiedLanguages = identifiedLanguages => {
21
21
  throw new Error(errMsg);
22
22
  }
23
23
  };
24
- exports.checkForMultipleIdentifiedLanguages = checkForMultipleIdentifiedLanguages;
24
+ exports.checkForMultipleIdentifiedLanguages =
25
+ checkForMultipleIdentifiedLanguages;
@@ -21,4 +21,5 @@ const checkForMultipleIdentifiedProjectFiles = identifiedLanguages => {
21
21
  }
22
22
  }
23
23
  };
24
- exports.checkForMultipleIdentifiedProjectFiles = checkForMultipleIdentifiedProjectFiles;
24
+ exports.checkForMultipleIdentifiedProjectFiles =
25
+ checkForMultipleIdentifiedProjectFiles;
@@ -20,4 +20,5 @@ const checkIdentifiedLanguageHasProjectFile = identifiedLanguages => {
20
20
  }
21
21
  }
22
22
  };
23
- exports.checkIdentifiedLanguageHasProjectFile = checkIdentifiedLanguageHasProjectFile;
23
+ exports.checkIdentifiedLanguageHasProjectFile =
24
+ checkIdentifiedLanguageHasProjectFile;
@@ -15,6 +15,7 @@ const chalk = require('chalk');
15
15
  const saveFile = require('../../commands/audit/saveFile').default;
16
16
  const generateSbom = require('../../sbom/generateSbom').default;
17
17
  const { failSpinner, returnOra, startSpinner, succeedSpinner } = require('../../utils/oraWrapper');
18
+ const { pollForSnapshotCompletition } = require('./sendSnapshot');
18
19
  module.exports = exports = (err, analysis) => {
19
20
  const { identifiedLanguageInfo } = analysis.languageAnalysis;
20
21
  const catalogueAppId = analysis.languageAnalysis.appId;
@@ -39,6 +40,7 @@ module.exports = exports = (err, analysis) => {
39
40
  const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
40
41
  startSpinner(reportSpinner);
41
42
  const snapshotResponse = await newSendSnapShot(analysis, catalogueAppId);
43
+ const pollResult = await pollForSnapshotCompletition(analysis.config, snapshotResponse.id, reportSpinner);
42
44
  succeedSpinner(reportSpinner, 'Contrast SCA analysis complete');
43
45
  await vulnerabilityReport(analysis, catalogueAppId, snapshotResponse.id);
44
46
  await auditSave(config);
@@ -38,6 +38,14 @@ const deduceLanguageScaAnalysis = filenames => {
38
38
  deducedLanguages.push(filename);
39
39
  language = NODE;
40
40
  }
41
+ if (isRubyProjectFilename(filename)) {
42
+ deducedLanguages.push(filename);
43
+ language = RUBY;
44
+ }
45
+ if (isPythonProjectFilename(filename)) {
46
+ deducedLanguages.push(filename);
47
+ language = PYTHON;
48
+ }
41
49
  if (isNodeLockFilename(filename)) {
42
50
  deducedLanguages.push(filename);
43
51
  language = NODE;
@@ -118,7 +126,8 @@ module.exports = exports = (analysis, next) => {
118
126
  }
119
127
  let language = config.language;
120
128
  if (language === undefined) {
121
- languageAnalysis.identifiedLanguages = reduceIdentifiedLanguages(identifiedLanguages);
129
+ languageAnalysis.identifiedLanguages =
130
+ reduceIdentifiedLanguages(identifiedLanguages);
122
131
  }
123
132
  else {
124
133
  let refinedIdentifiedLanguages = [];
@@ -28,7 +28,8 @@ function findCVESeverity(cve) {
28
28
  else if (cve.cvss3SeverityCode === 'HIGH' || cve.severityCode === 'HIGH') {
29
29
  return new reportSeverityModel_1.ReportSeverityModel('HIGH', constants_2.HIGH_PRIORITY, constants_2.HIGH_COLOUR, cveName);
30
30
  }
31
- else if (cve.cvss3SeverityCode === 'MEDIUM' || cve.severityCode === 'MEDIUM') {
31
+ else if (cve.cvss3SeverityCode === 'MEDIUM' ||
32
+ cve.severityCode === 'MEDIUM') {
32
33
  return new reportSeverityModel_1.ReportSeverityModel('MEDIUM', constants_2.MEDIUM_PRIORITY, constants_2.MEDIUM_COLOUR, cveName);
33
34
  }
34
35
  else if (cve.cvss3SeverityCode === 'LOW' || cve.severityCode === 'LOW') {
@@ -58,24 +59,20 @@ function severityCountAllCVEs(cveArray, severityCount) {
58
59
  }
59
60
  exports.severityCountAllCVEs = severityCountAllCVEs;
60
61
  function severityCountSingleCVE(cve, severityCount) {
61
- if (cve.cvss3SeverityCode === 'CRITICAL' ||
62
- cve.severityCode === 'CRITICAL') {
62
+ if (cve.cvss3SeverityCode === 'CRITICAL' || cve.severityCode === 'CRITICAL') {
63
63
  severityCount.critical += 1;
64
64
  }
65
- else if (cve.cvss3SeverityCode === 'HIGH' ||
66
- cve.severityCode === 'HIGH') {
65
+ else if (cve.cvss3SeverityCode === 'HIGH' || cve.severityCode === 'HIGH') {
67
66
  severityCount.high += 1;
68
67
  }
69
68
  else if (cve.cvss3SeverityCode === 'MEDIUM' ||
70
69
  cve.severityCode === 'MEDIUM') {
71
70
  severityCount.medium += 1;
72
71
  }
73
- else if (cve.cvss3SeverityCode === 'LOW' ||
74
- cve.severityCode === 'LOW') {
72
+ else if (cve.cvss3SeverityCode === 'LOW' || cve.severityCode === 'LOW') {
75
73
  severityCount.low += 1;
76
74
  }
77
- else if (cve.cvss3SeverityCode === 'NOTE' ||
78
- cve.severityCode === 'NOTE') {
75
+ else if (cve.cvss3SeverityCode === 'NOTE' || cve.severityCode === 'NOTE') {
79
76
  severityCount.note += 1;
80
77
  }
81
78
  return severityCount;
@@ -1,7 +1,13 @@
1
1
  "use strict";
2
- const { getHttpClient } = require('../../utils/commonApi');
3
2
  const { handleResponseErrors } = require('../../common/errorHandling');
4
3
  const { APP_VERSION } = require('../../constants/constants');
4
+ const commonApi = require('../../utils/commonApi');
5
+ const _ = require('lodash');
6
+ const oraFunctions = require('../../utils/oraWrapper');
7
+ const i18n = require('i18n');
8
+ const oraWrapper = require('../../utils/oraWrapper');
9
+ const requestUtils = require('../../utils/requestUtils');
10
+ const { performance } = require('perf_hooks');
5
11
  const newSendSnapShot = async (analysis) => {
6
12
  const analysisLanguage = analysis.config.language.toLowerCase();
7
13
  const requestBody = {
@@ -9,7 +15,7 @@ const newSendSnapShot = async (analysis) => {
9
15
  cliVersion: APP_VERSION,
10
16
  snapshot: { [analysisLanguage]: analysis[analysisLanguage] }
11
17
  };
12
- const client = getHttpClient(analysis.config);
18
+ const client = commonApi.getHttpClient(analysis.config);
13
19
  return client
14
20
  .sendSnapshot(requestBody, analysis.config)
15
21
  .then(res => {
@@ -24,6 +30,62 @@ const newSendSnapShot = async (analysis) => {
24
30
  console.log(err);
25
31
  });
26
32
  };
33
+ const pollSnapshotResults = async (config, snapshotId, client) => {
34
+ await requestUtils.sleep(5000);
35
+ return client
36
+ .getReportStatusById(config, snapshotId)
37
+ .then(res => {
38
+ return res;
39
+ })
40
+ .catch(err => {
41
+ console.log(err);
42
+ });
43
+ };
44
+ const getTimeout = config => {
45
+ if (config.timeout) {
46
+ return config.timeout;
47
+ }
48
+ else {
49
+ if (config.verbose) {
50
+ console.log('Timeout set to 2 minutes');
51
+ }
52
+ return 120;
53
+ }
54
+ };
55
+ const pollForSnapshotCompletition = async (config, snapshotId, reportSpinner) => {
56
+ const client = commonApi.getHttpClient(config);
57
+ const startTime = performance.now();
58
+ const timeout = getTimeout(config);
59
+ let complete = false;
60
+ if (!_.isNil(snapshotId)) {
61
+ while (!complete) {
62
+ let result = await pollSnapshotResults(config, snapshotId, client);
63
+ if (result.statusCode === 200) {
64
+ if (result.body.status === 'PROCESSED') {
65
+ complete = true;
66
+ return result.body;
67
+ }
68
+ if (result.body.status === 'FAILED') {
69
+ complete = true;
70
+ if (config.debug) {
71
+ oraFunctions.failSpinner(reportSpinner, i18n.__('auditNotCompleted'));
72
+ }
73
+ console.log(result.body.errorMessage);
74
+ oraWrapper.stopSpinner(reportSpinner);
75
+ console.log('Contrast audit finished');
76
+ process.exit(1);
77
+ }
78
+ }
79
+ const endTime = performance.now() - startTime;
80
+ if (requestUtils.millisToSeconds(endTime) > timeout) {
81
+ oraFunctions.failSpinner(reportSpinner, 'Contrast audit timed out at the specified ' + timeout + ' seconds.');
82
+ console.log('Please try again, allowing more time.');
83
+ process.exit(1);
84
+ }
85
+ }
86
+ }
87
+ };
27
88
  module.exports = {
28
- newSendSnapShot: newSendSnapShot
89
+ newSendSnapShot: newSendSnapShot,
90
+ pollForSnapshotCompletition: pollForSnapshotCompletition
29
91
  };
@@ -7,7 +7,7 @@ const help_1 = require("./help");
7
7
  const processAudit = async (argv) => {
8
8
  if (argv.indexOf('--help') != -1) {
9
9
  printHelpMessage();
10
- process.exit(1);
10
+ process.exit(0);
11
11
  }
12
12
  const config = (0, auditConfig_1.getAuditConfig)(argv);
13
13
  const auditResults = await (0, auditController_1.startAudit)(config);
@@ -4,15 +4,18 @@ const javaAnalysis = require('../../../scaAnalysis/java');
4
4
  const treeUpload = require('../../../scaAnalysis/common/treeUpload');
5
5
  const { manualDetectAuditFilesAndLanguages } = require('../../../scan/autoDetection');
6
6
  const auditController = require('../../audit/auditController');
7
- const { supportedLanguages: { JAVA, GO } } = require('../../../audit/languageAnalysisEngine/constants');
7
+ const { supportedLanguages: { JAVA, GO, RUBY, PYTHON } } = require('../../../audit/languageAnalysisEngine/constants');
8
8
  const goAnalysis = require('../../../scaAnalysis/go/goAnalysis');
9
+ const { rubyAnalysis } = require('../../../scaAnalysis/ruby');
10
+ const { pythonAnalysis } = require('../../../scaAnalysis/python');
9
11
  const processSca = async (config) => {
10
12
  let filesFound;
11
13
  if (config.projectPath) {
12
- filesFound = await manualDetectAuditFilesAndLanguages(config.projectPath);
14
+ filesFound = manualDetectAuditFilesAndLanguages(config.projectPath);
13
15
  }
14
16
  else {
15
17
  filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config);
18
+ config.projectPath = process.cwd();
16
19
  }
17
20
  let messageToSend = undefined;
18
21
  if (filesFound.length === 1) {
@@ -21,6 +24,14 @@ const processSca = async (config) => {
21
24
  messageToSend = javaAnalysis.javaAnalysis(config, filesFound[0]);
22
25
  config.language = JAVA;
23
26
  break;
27
+ case RUBY:
28
+ messageToSend = rubyAnalysis(config, filesFound[0]);
29
+ config.language = RUBY;
30
+ break;
31
+ case PYTHON:
32
+ messageToSend = pythonAnalysis(config, filesFound[0]);
33
+ config.language = PYTHON;
34
+ break;
24
35
  case GO:
25
36
  messageToSend = goAnalysis.goAnalysis(config, filesFound[0]);
26
37
  config.language = GO;
@@ -20,7 +20,8 @@ function HTTPClient(config) {
20
20
  Authorization: authToken,
21
21
  'API-Key': apiKey,
22
22
  SuperAuthorization: superAuthToken,
23
- 'Super-API-Key': superApiKey
23
+ 'Super-API-Key': superApiKey,
24
+ 'User-Agent': 'contrast-cli-v2'
24
25
  }
25
26
  };
26
27
  if (config.proxy) {
@@ -66,10 +67,24 @@ HTTPClient.prototype.getSpecificScanResult = function getSpecificScanResult(conf
66
67
  options.url = url;
67
68
  return requestUtils.sendRequest({ method: 'get', options });
68
69
  };
69
- HTTPClient.prototype.getSpecificScanResultSarif = function getSpecificScanResultSarif(config, scanId) {
70
+ HTTPClient.prototype.getSpecificScanResultSarif =
71
+ function getSpecificScanResultSarif(config, scanId) {
72
+ const options = _.cloneDeep(this.requestOptions);
73
+ options.url = createRawOutputURL(config, scanId);
74
+ return requestUtils.sendRequest({ method: 'get', options });
75
+ };
76
+ HTTPClient.prototype.createNewEvent = function createNewEvent(config, scanId, newProject) {
70
77
  const options = _.cloneDeep(this.requestOptions);
71
- options.url = createRawOutputURL(config, scanId);
72
- return requestUtils.sendRequest({ method: 'get', options });
78
+ options.url = createEventCollectorURL(config, scanId);
79
+ options.body = {
80
+ eventSource: process.env.CODESEC_INVOCATION_ENVIRONMENT,
81
+ trackingProperties: {
82
+ projectNameSource: config.projectNameSource,
83
+ waitedForResults: !config.ff,
84
+ newProject
85
+ }
86
+ };
87
+ return requestUtils.sendRequest({ method: 'post', options });
73
88
  };
74
89
  HTTPClient.prototype.getScanId = function getScanId(config, codeArtifactId) {
75
90
  const options = _.cloneDeep(this.requestOptions);
@@ -145,8 +160,6 @@ HTTPClient.prototype.catalogueCommand = function catalogueCommand(config) {
145
160
  return requestUtils.sendRequest({ method: 'post', options });
146
161
  };
147
162
  HTTPClient.prototype.sendSnapshot = function sendSnapshot(requestBody, config) {
148
- if (config.language.toUpperCase() === 'RUBY') {
149
- }
150
163
  const options = _.cloneDeep(this.requestOptions);
151
164
  let url = createSnapshotURL(config);
152
165
  options.url = url;
@@ -163,12 +176,18 @@ HTTPClient.prototype.getReportById = function getReportById(config, reportId) {
163
176
  }
164
177
  return requestUtils.sendRequest({ method: 'get', options });
165
178
  };
166
- HTTPClient.prototype.getLibraryVulnerabilities = function getLibraryVulnerabilities(config, requestBody) {
179
+ HTTPClient.prototype.getReportStatusById = function getReportStatusById(config, snapshotId) {
167
180
  const options = _.cloneDeep(this.requestOptions);
168
- options.url = createLibraryVulnerabilitiesUrl(config);
169
- options.body = requestBody;
170
- return requestUtils.sendRequest({ method: 'put', options });
181
+ options.url = createSpecificReportStatusURL(config, snapshotId);
182
+ return requestUtils.sendRequest({ method: 'get', options });
171
183
  };
184
+ HTTPClient.prototype.getLibraryVulnerabilities =
185
+ function getLibraryVulnerabilities(config, requestBody) {
186
+ const options = _.cloneDeep(this.requestOptions);
187
+ options.url = createLibraryVulnerabilitiesUrl(config);
188
+ options.body = requestBody;
189
+ return requestUtils.sendRequest({ method: 'put', options });
190
+ };
172
191
  HTTPClient.prototype.getAppId = function getAppId(config) {
173
192
  const options = _.cloneDeep(this.requestOptions);
174
193
  let url = createAppNameUrl(config);
@@ -210,11 +229,12 @@ HTTPClient.prototype.getScanResources = async function getScanResources(config,
210
229
  const options = { ...this.requestOptions, url };
211
230
  return requestUtils.sendRequest({ method: 'get', options });
212
231
  };
213
- HTTPClient.prototype.getFunctionScanResults = async function getFunctionScanResults(config, params, scanId, functionArn) {
214
- const url = createScanResultsGetUrl(config, params, scanId, functionArn);
215
- const options = { ...this.requestOptions, url };
216
- return requestUtils.sendRequest({ method: 'get', options });
217
- };
232
+ HTTPClient.prototype.getFunctionScanResults =
233
+ async function getFunctionScanResults(config, params, scanId, functionArn) {
234
+ const url = createScanResultsGetUrl(config, params, scanId, functionArn);
235
+ const options = { ...this.requestOptions, url };
236
+ return requestUtils.sendRequest({ method: 'get', options });
237
+ };
218
238
  HTTPClient.prototype.checkLibrary = function checkLibrary(data) {
219
239
  const options = _.cloneDeep(this.requestOptions);
220
240
  let url = createDataUrl();
@@ -227,6 +247,15 @@ HTTPClient.prototype.getSbom = function getSbom(config) {
227
247
  options.url = createSbomCycloneDXUrl(config);
228
248
  return requestUtils.sendRequest({ method: 'get', options });
229
249
  };
250
+ HTTPClient.prototype.postAnalyticsFunction = function (config, provider, body) {
251
+ const url = createAnalyticsFunctionPostUrl(config, provider);
252
+ const options = { ...this.requestOptions, body, url };
253
+ return requestUtils.sendRequest({ method: 'post', options });
254
+ };
255
+ const createAnalyticsFunctionPostUrl = (config, provider) => {
256
+ const url = getServerlessHost(config);
257
+ return `${url}/organizations/${config.organizationId}/providers/${provider}/analytics`;
258
+ };
230
259
  const createGetScanIdURL = config => {
231
260
  return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/scans/`;
232
261
  };
@@ -248,6 +277,9 @@ function createHarmonyProjectsUrl(config) {
248
277
  function createScanProjectUrl(config) {
249
278
  return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}`;
250
279
  }
280
+ const createEventCollectorURL = (config, scanId) => {
281
+ return `${config.host}/Contrast/api/sast/organizations/${config.organizationId}/projects/${config.projectId}/scans/${scanId}/events`;
282
+ };
251
283
  const createGlobalPropertiesUrl = protocol => {
252
284
  return `${protocol}/Contrast/api/ng/global/properties`;
253
285
  };
@@ -272,6 +304,9 @@ function createSpecificReportUrl(config, reportId) {
272
304
  function createSpecificReportWithProdUrl(config, reportId) {
273
305
  return createSpecificReportUrl(config, reportId).concat(`?nodesToInclude=PROD`);
274
306
  }
307
+ function createSpecificReportStatusURL(config, reportId) {
308
+ return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/${config.applicationId}/snapshots/${reportId}/status`;
309
+ }
275
310
  function createDataUrl() {
276
311
  return `https://ardy.contrastsecurity.com/production`;
277
312
  }
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.reportFailureError = exports.vulnerabilitiesFailureError = exports.snapshotFailureError = exports.findCommandOnError = exports.libraryAnalysisError = exports.handleResponseErrors = exports.getErrorMessage = exports.generalError = exports.failOptionError = exports.proxyError = exports.forbiddenError = exports.badRequestError = exports.unauthenticatedError = exports.genericError = void 0;
6
+ exports.maxAppError = exports.reportFailureError = exports.vulnerabilitiesFailureError = exports.snapshotFailureError = exports.findCommandOnError = exports.libraryAnalysisError = exports.handleResponseErrors = exports.getErrorMessage = exports.generalError = exports.failOptionError = exports.proxyError = exports.forbiddenError = exports.badRequestError = exports.unauthenticatedError = exports.genericError = void 0;
7
7
  const i18n_1 = __importDefault(require("i18n"));
8
8
  const handleResponseErrors = (res, api) => {
9
9
  if (res.statusCode === 400) {
@@ -72,6 +72,11 @@ const proxyError = () => {
72
72
  generalError('proxyErrorHeader', 'proxyErrorMessage');
73
73
  };
74
74
  exports.proxyError = proxyError;
75
+ const maxAppError = () => {
76
+ generalError('No applications remaining', 'You have reached the maximum number of application you can create.');
77
+ process.exit(1);
78
+ };
79
+ exports.maxAppError = maxAppError;
75
80
  const failOptionError = () => {
76
81
  console.log('\n ******************************** ' +
77
82
  i18n_1.default.__('snapshotFailureHeader') +
@@ -27,6 +27,6 @@ async function findLatestCLIVersion(updateMessageHidden) {
27
27
  }
28
28
  exports.findLatestCLIVersion = findLatestCLIVersion;
29
29
  async function isCorrectNodeVersion(currentVersion) {
30
- return semver_1.default.satisfies(currentVersion, '>=16.13.2 <17');
30
+ return semver_1.default.satisfies(currentVersion, '>=16');
31
31
  }
32
32
  exports.isCorrectNodeVersion = isCorrectNodeVersion;
@@ -12,7 +12,7 @@ const MEDIUM = 'MEDIUM';
12
12
  const HIGH = 'HIGH';
13
13
  const CRITICAL = 'CRITICAL';
14
14
  const APP_NAME = 'contrast';
15
- const APP_VERSION = '1.0.6';
15
+ const APP_VERSION = '1.0.7';
16
16
  const TIMEOUT = 120000;
17
17
  const HIGH_COLOUR = '#ff9900';
18
18
  const CRITICAL_COLOUR = '#e35858';
@@ -96,7 +96,7 @@ const en_locales = () => {
96
96
  constantsCount: "The number of CVE's that must be exceeded to fail a build",
97
97
  constantsHeader: 'CodeSec by Contrast Security',
98
98
  constantsPrerequisitesContentScanLanguages: 'Java & JavaScript supported',
99
- constantsContrastContent: 'Use the Contrast CLI to run a scan (Java, JavaScript and .NET ) or lambda command (Java and Python) to find your vulnerabilities and start securing your code.',
99
+ constantsContrastContent: "Use the 'contrast' command for fast and accurate security analysis of your applications and APIs (Java, JavaScript and .NET ) as well as serverless functions (AWS lambda, Java and Python).",
100
100
  constantsUsageGuideContentRecommendation: 'Our recommendation is that this is invoked as part of a CI pipeline so that running the cli is automated as part of your build process.',
101
101
  constantsPrerequisitesHeader: 'Pre-requisites',
102
102
  constantsAuthUsageHeader: 'Usage',
@@ -247,6 +247,7 @@ const en_locales = () => {
247
247
  redirectAuth: '\nOpening the authentication page in your web browser.\nSign in and complete the steps.\nReturn here to start using Contrast.\n\nIf your browser has trouble loading, try this:\n%s \n',
248
248
  scanZipError: 'A .zip archive can be used for Javascript Scan. Archive found %s does not contain .JS files for Scan.',
249
249
  fileNotExist: 'File specified does not exist, please check and try again.',
250
+ scanFileIsEmpty: 'File specified is empty. Please choose another.',
250
251
  fileHasWhiteSpacesError: 'File cannot have spaces, please rename or choose another file to Scan.',
251
252
  zipFileException: 'Error reading zip file',
252
253
  connectionError: 'An error has occurred when trying to get the Project Id please check your internet connection or provide the Project Id manually',
@@ -278,6 +279,7 @@ const en_locales = () => {
278
279
  auditOptionsSave: '-s, --save',
279
280
  auditOptionsSaveDescription: 'saves the output in specified format Txt text, sbom',
280
281
  scanNotCompleted: 'Scan not completed. Check for framework and language support here: %s',
282
+ auditNotCompleted: 'audit not completed. Please try again',
281
283
  scanNoVulnerabilitiesFound: '👏 No vulnerabilities found',
282
284
  scanNoVulnerabilitiesFoundSecureCode: '👍 Your code looks secure.',
283
285
  scanNoVulnerabilitiesFoundGoodWork: '👏 Keep up the good work.',
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.postAnalytics = void 0;
4
+ const commonApi_1 = require("../utils/commonApi");
5
+ const paramHandler_1 = require("../utils/paramsUtil/paramHandler");
6
+ const postAnalytics = (data, provider = 'aws') => {
7
+ const config = (0, paramHandler_1.getAuth)();
8
+ const client = (0, commonApi_1.getHttpClient)(config);
9
+ return client.postAnalyticsFunction(config, provider, data);
10
+ };
11
+ exports.postAnalytics = postAnalytics;
@@ -20,6 +20,8 @@ const utils_1 = require("./utils");
20
20
  const lambdaUtils_1 = require("./lambdaUtils");
21
21
  const requestUtils_1 = require("../utils/requestUtils");
22
22
  const oraWrapper_1 = __importDefault(require("../utils/oraWrapper"));
23
+ const analytics_1 = require("./analytics");
24
+ const types_1 = require("./types");
23
25
  const failedStates = [
24
26
  'UNSUPPORTED',
25
27
  'EXCLUDED',
@@ -57,9 +59,19 @@ const getLambdaOptions = (argv) => {
57
59
  }
58
60
  };
59
61
  const processLambda = async (argv) => {
62
+ let errorMsg;
63
+ let scanInfo;
64
+ const commandSessionId = Date.now().toString(36);
60
65
  try {
61
66
  const lambdaOptions = getLambdaOptions(argv);
62
67
  const { help } = lambdaOptions;
68
+ const startCommandAnalytics = {
69
+ arguments: lambdaOptions,
70
+ sessionId: commandSessionId,
71
+ eventType: types_1.EventType.START
72
+ };
73
+ (0, analytics_1.postAnalytics)(startCommandAnalytics).catch((error) => {
74
+ });
63
75
  if (help) {
64
76
  return handleLambdaHelp();
65
77
  }
@@ -68,17 +80,35 @@ const processLambda = async (argv) => {
68
80
  await getAvailableFunctions(lambdaOptions);
69
81
  }
70
82
  else {
71
- await actualProcessLambda(lambdaOptions);
83
+ scanInfo = await actualProcessLambda(lambdaOptions);
72
84
  }
73
85
  }
74
86
  catch (error) {
75
87
  if (error instanceof cliError_1.CliError) {
76
- console.error(error.getErrorMessage());
88
+ errorMsg = error.getErrorMessage();
77
89
  }
78
90
  else if (error instanceof Error) {
79
- console.error(error.message);
91
+ errorMsg = error.message;
92
+ }
93
+ }
94
+ finally {
95
+ const endCommandAnalytics = {
96
+ sessionId: commandSessionId,
97
+ eventType: types_1.EventType.END,
98
+ status: errorMsg ? types_1.StatusType.FAILED : types_1.StatusType.SUCCESS
99
+ };
100
+ if (errorMsg) {
101
+ endCommandAnalytics.errorMsg = errorMsg;
102
+ console.error(errorMsg);
103
+ }
104
+ if (scanInfo) {
105
+ endCommandAnalytics.scanFunctionData = scanInfo;
106
+ }
107
+ await (0, analytics_1.postAnalytics)(endCommandAnalytics).catch((error) => {
108
+ });
109
+ if (errorMsg) {
110
+ process.exit(1);
80
111
  }
81
- process.exit(1);
82
112
  }
83
113
  };
84
114
  exports.processLambda = processLambda;
@@ -127,6 +157,7 @@ const actualProcessLambda = async (lambdaOptions) => {
127
157
  if (results?.length) {
128
158
  (0, utils_1.printResults)(results);
129
159
  }
160
+ return { functionArn, scanId };
130
161
  };
131
162
  const validateRequiredLambdaParams = (options) => {
132
163
  if (options._unknown?.length) {
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EventType = exports.StatusType = void 0;
4
+ var StatusType;
5
+ (function (StatusType) {
6
+ StatusType["FAILED"] = "failed";
7
+ StatusType["SUCCESS"] = "success";
8
+ })(StatusType = exports.StatusType || (exports.StatusType = {}));
9
+ var EventType;
10
+ (function (EventType) {
11
+ EventType["START"] = "start_command_session";
12
+ EventType["END"] = "end_command_session";
13
+ })(EventType = exports.EventType || (exports.EventType = {}));
@@ -13,7 +13,23 @@ const createGoTSMessage = goTree => {
13
13
  }
14
14
  };
15
15
  };
16
+ const createRubyTSMessage = rubyTree => {
17
+ return {
18
+ ruby: {
19
+ rubyDependencyTrees: rubyTree
20
+ }
21
+ };
22
+ };
23
+ const createPythonTSMessage = pythonTree => {
24
+ return {
25
+ python: {
26
+ pythonDependencyTrees: pythonTree
27
+ }
28
+ };
29
+ };
16
30
  module.exports = {
17
31
  createJavaTSMessage,
18
- createGoTSMessage
32
+ createGoTSMessage,
33
+ createRubyTSMessage,
34
+ createPythonTSMessage
19
35
  };
@@ -9,16 +9,13 @@ const determineProjectTypeAndCwd = (files, projectPath) => {
9
9
  const projectData = {};
10
10
  if (files[0].includes('pom.xml')) {
11
11
  projectData.projectType = MAVEN;
12
- projectData.cwd = projectPath
13
- ? projectPath
14
- : files[0].replace('pom.xml', '');
15
12
  }
16
13
  else if (files[0].includes('build.gradle')) {
17
14
  projectData.projectType = GRADLE;
18
- projectData.cwd = projectPath
19
- ? projectPath
20
- : files[0].replace('pom.xml', '');
21
15
  }
16
+ projectData.cwd = projectPath
17
+ ? projectPath.replace('pom.xml', '').replace('build.gradle', '')
18
+ : projectPath;
22
19
  return projectData;
23
20
  };
24
21
  const buildMaven = (config, projectData, timeout) => {
@@ -3,10 +3,10 @@ const analysis = require('./analysis');
3
3
  const { parseBuildDeps } = require('./javaBuildDepsParser');
4
4
  const { createJavaTSMessage } = require('../common/formatMessage');
5
5
  const javaAnalysis = (config, languageFiles) => {
6
- languageFiles.java.forEach(file => {
6
+ languageFiles.JAVA.forEach(file => {
7
7
  file.replace('build.gradle.kts', 'build.gradle');
8
8
  });
9
- const javaDeps = buildJavaTree(config, languageFiles.java);
9
+ const javaDeps = buildJavaTree(config, languageFiles.JAVA);
10
10
  return createJavaTSMessage(javaDeps);
11
11
  };
12
12
  const buildJavaTree = (config, files) => {