@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
package/README.md CHANGED
@@ -10,7 +10,7 @@ CodeSec delivers:
10
10
  ## Install
11
11
 
12
12
  ```shell
13
- npm install -g @contrast/contrast
13
+ npm install --location=global @contrast/contrast
14
14
  ```
15
15
 
16
16
  ## Authenticate
@@ -52,7 +52,7 @@ export AWS_SECRET_ACCESS_KEY=<YOUR_SECRET_ACCESS_KEY>
52
52
 
53
53
  - These permissions are required to gather all required information on an AWS Lambda to use the `contrast lambda` command:
54
54
 
55
- - Lambda: [GetFunction](https://docs.aws.amazon.com/lambda/latest/dg/API_GetFunction.html) | [GetLayerVersion](https://docs.aws.amazon.com/lambda/latest/dg/API_GetLayerVersion.html)
55
+ - Lambda: [GetFunction](https://docs.aws.amazon.com/lambda/latest/dg/API_GetFunction.html) | [GetLayerVersion](https://docs.aws.amazon.com/lambda/latest/dg/API_GetLayerVersion.html) | [ListFunctions](https://docs.aws.amazon.com/lambda/latest/dg/API_ListFunctions.html)
56
56
  - IAM: [GetRolePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetRolePolicy.html) | [GetPolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetPolicy.html) | [GetPolicyVersion](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetPolicyVersion.html) | [ListRolePolicies](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListRolePolicies.html) | [ListAttachedRolePolicies](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAttachedRolePolicies.html)
57
57
 
58
58
  ### Start scanning
@@ -2,29 +2,29 @@
2
2
  const fs = require('fs');
3
3
  const path = require('path');
4
4
  const i18n = require('i18n');
5
- const getProjectRootFilenames = file => {
6
- let projectStats = null;
5
+ const getDirectoryFromPathGiven = file => {
6
+ let projectStats = getProjectStats(file);
7
+ if (projectStats.isFile()) {
8
+ let newPath = path.resolve(file);
9
+ return path.dirname(newPath);
10
+ }
11
+ if (projectStats.isDirectory()) {
12
+ return file;
13
+ }
14
+ };
15
+ const getProjectStats = file => {
7
16
  try {
8
- projectStats = fs.statSync(file);
17
+ if (file.endsWith('/')) {
18
+ file = file.slice(0, -1);
19
+ }
20
+ return fs.statSync(file);
9
21
  }
10
22
  catch (err) {
11
23
  throw new Error(i18n.__('languageAnalysisProjectRootFileNameFailure', file) +
12
24
  `${err.message}`);
13
25
  }
14
- if (projectStats.isDirectory()) {
15
- try {
16
- return fs.readdirSync(file);
17
- }
18
- catch (err) {
19
- throw new Error(i18n.__('languageAnalysisProjectRootFileNameReadError', file) +
20
- `${err.message}`);
21
- }
22
- }
23
- if (projectStats.isFile()) {
24
- return [path.basename(file)];
25
- }
26
- throw new Error(i18n.__('languageAnalysisProjectRootFileNameMissingError'), file);
27
26
  };
28
27
  module.exports = {
29
- getProjectRootFilenames
28
+ getProjectStats,
29
+ getDirectoryFromPathGiven: getDirectoryFromPathGiven
30
30
  };
@@ -3,22 +3,29 @@ 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.getNumOfAndSeverityType = exports.buildFormattedHeaderNum = exports.gatherRemediationAdvice = exports.buildBody = exports.buildHeader = exports.printFormattedOutput = exports.printVulnerabilityResponse = exports.getReport = exports.createSummaryMessage = void 0;
7
- const commonApi_1 = require("../../../utils/commonApi");
6
+ exports.getNumOfAndSeverityType = exports.buildFormattedHeaderNum = exports.gatherRemediationAdvice = exports.buildBody = exports.buildHeader = exports.printFormattedOutput = exports.printVulnerabilityResponse = exports.getReport = exports.createSummaryMessageBottom = exports.createSummaryMessageTop = void 0;
7
+ const commonApi_1 = require("../../utils/commonApi");
8
8
  const reportListModel_1 = require("./models/reportListModel");
9
9
  const lodash_1 = require("lodash");
10
10
  const chalk_1 = __importDefault(require("chalk"));
11
11
  const reportUtils_1 = require("./utils/reportUtils");
12
12
  const severityCountModel_1 = require("./models/severityCountModel");
13
13
  const reportOutputModel_1 = require("./models/reportOutputModel");
14
- const constants_1 = require("../../../constants/constants");
14
+ const constants_1 = require("../../constants/constants");
15
15
  const cli_table3_1 = __importDefault(require("cli-table3"));
16
- const createSummaryMessage = (numberOfVulnerableLibraries, numberOfCves) => {
16
+ const reportGuidanceModel_1 = require("./models/reportGuidanceModel");
17
+ const createSummaryMessageTop = (numberOfVulnerableLibraries, numberOfCves) => {
17
18
  numberOfVulnerableLibraries === 1
18
19
  ? console.log(`Found 1 vulnerable library containing ${numberOfCves} CVE`)
19
20
  : console.log(`Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVEs`);
20
21
  };
21
- exports.createSummaryMessage = createSummaryMessage;
22
+ exports.createSummaryMessageTop = createSummaryMessageTop;
23
+ const createSummaryMessageBottom = (numberOfVulnerableLibraries) => {
24
+ numberOfVulnerableLibraries === 1
25
+ ? console.log(`Found 1 vulnerable library`)
26
+ : console.log(`Found ${numberOfVulnerableLibraries} vulnerable libraries`);
27
+ };
28
+ exports.createSummaryMessageBottom = createSummaryMessageBottom;
22
29
  const getReport = async (config, reportId) => {
23
30
  const client = (0, commonApi_1.getHttpClient)(config);
24
31
  return client
@@ -47,7 +54,7 @@ const printVulnerabilityResponse = (config, vulnerableLibraries, numberOfVulnera
47
54
  };
48
55
  exports.printVulnerabilityResponse = printVulnerabilityResponse;
49
56
  const printFormattedOutput = (config, libraries, numberOfVulnerableLibraries, numberOfCves, guidance) => {
50
- (0, exports.createSummaryMessage)(numberOfVulnerableLibraries, numberOfCves);
57
+ (0, exports.createSummaryMessageTop)(numberOfVulnerableLibraries, numberOfCves);
51
58
  console.log();
52
59
  const report = new reportListModel_1.ReportList();
53
60
  for (const library of libraries) {
@@ -92,24 +99,29 @@ const printFormattedOutput = (config, libraries, numberOfVulnerableLibraries, nu
92
99
  colWidths: [12, 1, 100]
93
100
  });
94
101
  const header = buildHeader(highestSeverity, contrastHeaderNumCounter, libraryName, libraryVersion, numOfCVEs);
95
- const advice = gatherRemediationAdvice(guidance, reportModel);
102
+ const advice = gatherRemediationAdvice(guidance, libraryName, libraryVersion);
96
103
  const body = buildBody(reportModel.cveArray, advice);
97
104
  const reportOutputModel = new reportOutputModel_1.ReportOutputModel(header, body);
98
- table.push(reportOutputModel.body.issueMessage, reportOutputModel.body.issueMessageCves, reportOutputModel.body.adviceMessage);
105
+ table.push(reportOutputModel.body.issueMessage, reportOutputModel.body.adviceMessage);
99
106
  console.log(reportOutputModel.header.vulnMessage, reportOutputModel.header.introducesMessage);
100
107
  console.log(table.toString() + '\n');
101
108
  }
102
- (0, exports.createSummaryMessage)(numberOfVulnerableLibraries, numberOfCves);
109
+ (0, exports.createSummaryMessageBottom)(numberOfVulnerableLibraries);
103
110
  const { criticalMessage, highMessage, mediumMessage, lowMessage, noteMessage } = buildFooter(outputOrderedByLowestSeverityAndLowestNumOfCvesFirst);
104
111
  console.log(`${criticalMessage} | ${highMessage} | ${mediumMessage} | ${lowMessage} | ${noteMessage}`);
112
+ if (config.host !== constants_1.CE_URL) {
113
+ console.log('\n' + chalk_1.default.bold('View your full dependency tree in Contrast:'));
114
+ console.log(`${config.host}/Contrast/static/ng/index.html#/${config.organizationId}/applications/${config.applicationId}/libs/dependency-tree`);
115
+ }
105
116
  };
106
117
  exports.printFormattedOutput = printFormattedOutput;
107
118
  function buildHeader(highestSeverity, contrastHeaderNum, libraryName, version, numOfCVEs) {
108
119
  const vulnerabilityPluralised = numOfCVEs > 1 ? 'vulnerabilities' : 'vulnerability';
109
120
  const formattedHeaderNum = buildFormattedHeaderNum(contrastHeaderNum);
110
- const vulnMessage = chalk_1.default
111
- .hex(highestSeverity.outputColour)
112
- .bold(`${formattedHeaderNum} - [${highestSeverity.severity}] ${libraryName}-${version}`);
121
+ const headerColour = chalk_1.default.hex(highestSeverity.outputColour);
122
+ const headerNumAndSeverity = headerColour(`${formattedHeaderNum} - [${highestSeverity.severity}]`);
123
+ const libraryNameAndVersion = headerColour.bold(`${libraryName}-${version}`);
124
+ const vulnMessage = `${headerNumAndSeverity} ${libraryNameAndVersion}`;
113
125
  const introducesMessage = `introduces ${numOfCVEs} ${vulnerabilityPluralised}`;
114
126
  return new reportOutputModel_1.ReportOutputHeaderModel(vulnMessage, introducesMessage);
115
127
  }
@@ -125,29 +137,27 @@ function buildBody(cveArray, advice) {
125
137
  cveMessages.push(builtMessage);
126
138
  });
127
139
  const numAndSeverityType = getNumOfAndSeverityType(cveArray);
128
- const issueMessage = [chalk_1.default.bold('Issue'), ':', `${numAndSeverityType}`];
129
- const issueMessageCves = ['', '', cveMessages.join(', ')];
130
- const displayAdvice = advice?.minimum
131
- ? `Update to version ${chalk_1.default.bold(advice.minimum)}`
132
- : `Update to latest version`;
140
+ const issueMessage = [
141
+ chalk_1.default.bold('Issue'),
142
+ ':',
143
+ `${numAndSeverityType} ${cveMessages.join(', ')}`
144
+ ];
145
+ const minOrMax = advice.maximum ? advice.maximum : advice.minimum;
146
+ const displayAdvice = minOrMax
147
+ ? `Change to version ${chalk_1.default.bold(minOrMax)}`
148
+ : 'No recommendation is available according to our data. Upgrade to the latest stable is the best advice we can give.';
133
149
  const adviceMessage = [chalk_1.default.bold('Advice'), ':', displayAdvice];
134
- return new reportOutputModel_1.ReportOutputBodyModel(issueMessage, issueMessageCves, adviceMessage);
150
+ return new reportOutputModel_1.ReportOutputBodyModel(issueMessage, adviceMessage);
135
151
  }
136
152
  exports.buildBody = buildBody;
137
- function gatherRemediationAdvice(guidance, reportModel) {
138
- const guidanceData = {
139
- minimum: undefined,
140
- maximum: undefined,
141
- latest: undefined
142
- };
143
- const data = guidance[reportModel.compositeKey.libraryName +
144
- '@' +
145
- reportModel.compositeKey.libraryVersion];
153
+ function gatherRemediationAdvice(guidance, libraryName, libraryVersion) {
154
+ const guidanceModel = new reportGuidanceModel_1.ReportGuidanceModel();
155
+ const data = guidance[libraryName + '@' + libraryVersion];
146
156
  if (data) {
147
- guidanceData.minimum = data.minUpgradeVersion;
148
- guidanceData.maximum = data.maxUpgradeVersion;
157
+ guidanceModel.minimum = data.minUpgradeVersion;
158
+ guidanceModel.maximum = data.maxUpgradeVersion;
149
159
  }
150
- return guidanceData;
160
+ return guidanceModel;
151
161
  }
152
162
  exports.gatherRemediationAdvice = gatherRemediationAdvice;
153
163
  function buildFormattedHeaderNum(contrastHeaderNum) {
@@ -156,11 +166,22 @@ function buildFormattedHeaderNum(contrastHeaderNum) {
156
166
  exports.buildFormattedHeaderNum = buildFormattedHeaderNum;
157
167
  function getNumOfAndSeverityType(cveArray) {
158
168
  const { critical, high, medium, low, note } = (0, reportUtils_1.severityCountAllCVEs)(cveArray, new severityCountModel_1.SeverityCountModel());
159
- const criticalMessage = critical > 0 ? `${critical} Critical` : '';
160
- const highMessage = high > 0 ? `${high} High` : '';
161
- const mediumMessage = medium > 0 ? `${medium} Medium` : '';
162
- const lowMessage = low > 0 ? `${low} Low` : '';
163
- const noteMessage = note > 0 ? `${note} Note` : '';
169
+ const criticalNumCheck = critical > 0;
170
+ const highNumCheck = high > 0;
171
+ const highDivider = highNumCheck ? '|' : '';
172
+ const mediumNumCheck = medium > 0;
173
+ const mediumDivider = mediumNumCheck ? '|' : '';
174
+ const lowNumCheck = low > 0;
175
+ const lowDivider = lowNumCheck ? '|' : '';
176
+ const noteNumCheck = low > 0;
177
+ const noteDivider = noteNumCheck ? '|' : '';
178
+ const criticalMessage = criticalNumCheck
179
+ ? `${critical} Critical ${highDivider}`
180
+ : '';
181
+ const highMessage = highNumCheck ? `${high} High ${mediumDivider}` : '';
182
+ const mediumMessage = mediumNumCheck ? `${medium} Medium ${lowDivider}` : '';
183
+ const lowMessage = lowNumCheck ? `${low} Low ${noteDivider}` : '';
184
+ const noteMessage = noteNumCheck ? `${note} Note` : '';
164
185
  return `${criticalMessage} ${highMessage} ${mediumMessage} ${lowMessage} ${noteMessage}`
165
186
  .replace(/\s+/g, ' ')
166
187
  .trim();
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReportGuidanceModel = void 0;
4
+ class ReportGuidanceModel {
5
+ }
6
+ exports.ReportGuidanceModel = ReportGuidanceModel;
@@ -16,9 +16,8 @@ class ReportOutputHeaderModel {
16
16
  }
17
17
  exports.ReportOutputHeaderModel = ReportOutputHeaderModel;
18
18
  class ReportOutputBodyModel {
19
- constructor(issueMessage, issueMessageCves, adviceMessage) {
19
+ constructor(issueMessage, adviceMessage) {
20
20
  this.issueMessage = issueMessage;
21
- this.issueMessageCves = issueMessageCves;
22
21
  this.adviceMessage = adviceMessage;
23
22
  }
24
23
  }
@@ -8,6 +8,7 @@ class SeverityCountModel {
8
8
  this.medium = 0;
9
9
  this.low = 0;
10
10
  this.note = 0;
11
+ this.total = 0;
11
12
  }
12
13
  get getTotal() {
13
14
  return this.critical + this.high + this.medium + this.low + this.note;
@@ -31,7 +31,9 @@ const commonReportingFunctions_1 = require("./commonReportingFunctions");
31
31
  const reportUtils_1 = require("./utils/reportUtils");
32
32
  const i18n_1 = __importDefault(require("i18n"));
33
33
  const chalk_1 = __importDefault(require("chalk"));
34
- const constants = __importStar(require("../../../constants/constants"));
34
+ const constants = __importStar(require("../../constants/constants"));
35
+ const severityCountModel_1 = require("./models/severityCountModel");
36
+ const common = __importStar(require("../../common/fail"));
35
37
  function convertKeysToStandardFormat(config, guidance) {
36
38
  let convertedGuidance = guidance;
37
39
  switch (config.language) {
@@ -70,16 +72,16 @@ function formatVulnerabilityOutput(libraryVulnerabilityResponse, id, config, rem
70
72
  console.log(i18n_1.default.__('scanNoVulnerabilitiesFoundGoodWork'));
71
73
  console.log(chalk_1.default.bold(`Found ${numberOfVulnerableLibraries} vulnerabilities`));
72
74
  console.log(i18n_1.default.__('foundDetailedVulnerabilities', String(0), String(0), String(0), String(0), String(0)));
75
+ return [false, 0, [new severityCountModel_1.SeverityCountModel()]];
73
76
  }
74
77
  else {
75
78
  let numberOfCves = 0;
76
79
  vulnerableLibraries.forEach(lib => (numberOfCves += lib.cveArray.length));
77
80
  const hasSomeVulnerabilitiesReported = (0, commonReportingFunctions_1.printVulnerabilityResponse)(config, vulnerableLibraries, numberOfVulnerableLibraries, numberOfCves, guidance);
78
- return [
79
- hasSomeVulnerabilitiesReported,
80
- numberOfCves,
81
- (0, reportUtils_1.severityCountAllLibraries)(vulnerableLibraries)
82
- ];
81
+ let severityCount = new severityCountModel_1.SeverityCountModel();
82
+ severityCount = (0, reportUtils_1.severityCountAllLibraries)(vulnerableLibraries, severityCount);
83
+ severityCount.total = severityCount.getTotal;
84
+ return [hasSomeVulnerabilitiesReported, numberOfCves, severityCount];
83
85
  }
84
86
  }
85
87
  exports.formatVulnerabilityOutput = formatVulnerabilityOutput;
@@ -87,10 +89,12 @@ async function vulnerabilityReportV2(config, reportId) {
87
89
  console.log();
88
90
  const reportResponse = await (0, commonReportingFunctions_1.getReport)(config, reportId);
89
91
  if (reportResponse !== undefined) {
90
- const name = config.applicationName;
91
- formatVulnerabilityOutput(reportResponse.vulnerabilities, config.applicationId, config, reportResponse.remediationGuidance
92
+ let output = formatVulnerabilityOutput(reportResponse.vulnerabilities, config.applicationId, config, reportResponse.remediationGuidance
92
93
  ? reportResponse.remediationGuidance
93
94
  : {});
95
+ if (config.fail) {
96
+ common.processFail(config, output[2]);
97
+ }
94
98
  }
95
99
  }
96
100
  exports.vulnerabilityReportV2 = vulnerabilityReportV2;
@@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.countVulnerableLibrariesBySeverity = exports.findNameAndVersion = exports.severityCountSingleCVE = exports.severityCountAllCVEs = exports.severityCountAllLibraries = exports.convertGenericToTypedLibraryVulns = exports.findCVESeverity = exports.findCVESeveritiesAndOrderByHighestPriority = exports.findHighestSeverityCVE = void 0;
7
7
  const reportLibraryModel_1 = require("../models/reportLibraryModel");
8
8
  const reportSeverityModel_1 = require("../models/reportSeverityModel");
9
- const constants_1 = __importDefault(require("./../../../../constants/constants"));
10
- const constants_2 = require("../../../../constants/constants");
9
+ const constants_1 = __importDefault(require("../../../constants/constants"));
10
+ const constants_2 = require("../../../constants/constants");
11
11
  const lodash_1 = require("lodash");
12
12
  const severityCountModel_1 = require("../models/severityCountModel");
13
13
  const { supportedLanguages: { GO } } = constants_1.default;
@@ -46,8 +46,7 @@ function convertGenericToTypedLibraryVulns(libraries) {
46
46
  });
47
47
  }
48
48
  exports.convertGenericToTypedLibraryVulns = convertGenericToTypedLibraryVulns;
49
- function severityCountAllLibraries(vulnerableLibraries) {
50
- const severityCount = new severityCountModel_1.SeverityCountModel();
49
+ function severityCountAllLibraries(vulnerableLibraries, severityCount) {
51
50
  vulnerableLibraries.forEach(lib => severityCountAllCVEs(lib.cveArray, severityCount));
52
51
  return severityCount;
53
52
  }
@@ -6,9 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getAuditConfig = void 0;
7
7
  const paramHandler_1 = __importDefault(require("../../utils/paramsUtil/paramHandler"));
8
8
  const constants_1 = __importDefault(require("../../constants"));
9
- const parsedCLIOptions_1 = __importDefault(require("../../utils/parsedCLIOptions"));
10
- const getAuditConfig = (argv) => {
11
- const auditParameters = parsedCLIOptions_1.default.getCommandLineArgsCustom(argv, constants_1.default.commandLineDefinitions.auditOptionDefinitions);
9
+ const parsedCLIOptions_1 = require("../../utils/parsedCLIOptions");
10
+ const getAuditConfig = async (contrastConf, command, argv) => {
11
+ const auditParameters = await (0, parsedCLIOptions_1.getCommandLineArgsCustom)(contrastConf, command, argv, constants_1.default.commandLineDefinitions.auditOptionDefinitions);
12
12
  const paramsAuth = paramHandler_1.default.getAuth(auditParameters);
13
13
  return { ...paramsAuth, ...auditParameters };
14
14
  };
@@ -7,6 +7,7 @@ exports.auditUsageGuide = void 0;
7
7
  const command_line_usage_1 = __importDefault(require("command-line-usage"));
8
8
  const i18n_1 = __importDefault(require("i18n"));
9
9
  const constants_1 = __importDefault(require("../../constants"));
10
+ const commonHelp_1 = require("../../common/commonHelp");
10
11
  const auditUsageGuide = (0, command_line_usage_1.default)([
11
12
  {
12
13
  header: i18n_1.default.__('auditHeader'),
@@ -53,6 +54,7 @@ const auditUsageGuide = (0, command_line_usage_1.default)([
53
54
  'app-groups',
54
55
  'metadata'
55
56
  ]
56
- }
57
+ },
58
+ (0, commonHelp_1.commonHelpLinks)()
57
59
  ]);
58
60
  exports.auditUsageGuide = auditUsageGuide;
@@ -4,13 +4,15 @@ exports.processAudit = void 0;
4
4
  const auditConfig_1 = require("./auditConfig");
5
5
  const help_1 = require("./help");
6
6
  const scaAnalysis_1 = require("../scan/sca/scaAnalysis");
7
- const processAudit = async (argv) => {
7
+ const telemetry_1 = require("../../telemetry/telemetry");
8
+ const processAudit = async (contrastConf, argv) => {
8
9
  if (argv.indexOf('--help') != -1) {
9
10
  printHelpMessage();
10
11
  process.exit(0);
11
12
  }
12
- const config = (0, auditConfig_1.getAuditConfig)(argv);
13
+ const config = await (0, auditConfig_1.getAuditConfig)(contrastConf, 'audit', argv);
13
14
  await (0, scaAnalysis_1.processSca)(config);
15
+ await (0, telemetry_1.sendTelemetryConfigAsObject)(config, 'audit', argv, 'SUCCESS', config.language);
14
16
  };
15
17
  exports.processAudit = processAudit;
16
18
  const printHelpMessage = () => {
@@ -11,7 +11,7 @@ const parsedCLIOptions = require('../../utils/parsedCLIOptions');
11
11
  const constants = require('../../constants');
12
12
  const commandLineUsage = require('command-line-usage');
13
13
  const processAuth = async (argv, config) => {
14
- let authParams = parsedCLIOptions.getCommandLineArgsCustom(argv, constants.commandLineDefinitions.authOptionDefinitions);
14
+ let authParams = await parsedCLIOptions.getCommandLineArgsCustom(config, 'auth', argv, constants.commandLineDefinitions.authOptionDefinitions);
15
15
  if (authParams.help) {
16
16
  console.log(authUsageGuide);
17
17
  process.exit(0);
@@ -3,9 +3,9 @@ const parsedCLIOptions = require('../../utils/parsedCLIOptions');
3
3
  const constants = require('../../constants');
4
4
  const commandLineUsage = require('command-line-usage');
5
5
  const i18n = require('i18n');
6
- const processConfig = (argv, config) => {
6
+ const processConfig = async (argv, config) => {
7
7
  try {
8
- let configParams = parsedCLIOptions.getCommandLineArgsCustom(argv, constants.commandLineDefinitions.configOptionDefinitions);
8
+ let configParams = await parsedCLIOptions.getCommandLineArgsCustom(config, 'config', argv, constants.commandLineDefinitions.configOptionDefinitions);
9
9
  if (configParams.help) {
10
10
  console.log(configUsageGuide);
11
11
  process.exit(0);
@@ -5,18 +5,25 @@ const { saveScanFile } = require('../../utils/saveFile');
5
5
  const { ScanResultsModel } = require('../../scan/models/scanResultsModel');
6
6
  const { formatScanOutput } = require('../../scan/formatScanOutput');
7
7
  const { processSca } = require('./sca/scaAnalysis');
8
- const processScan = async (argvMain) => {
9
- let config = scanConfig.getScanConfig(argvMain);
8
+ const common = require('../../common/fail');
9
+ const { sendTelemetryConfigAsObject } = require('../../telemetry/telemetry');
10
+ const processScan = async (contrastConf, argv) => {
11
+ let config = await scanConfig.getScanConfig(contrastConf, 'scan', argv);
12
+ let output = undefined;
10
13
  if (config.experimental) {
11
- await processSca(config);
14
+ await processSca(config, argv);
12
15
  }
13
16
  let scanResults = new ScanResultsModel(await startScan(config));
17
+ await sendTelemetryConfigAsObject(config, 'scan', argv, 'SUCCESS', scanResults.scanDetail.language);
14
18
  if (scanResults.scanResultsInstances !== undefined) {
15
- formatScanOutput(scanResults);
19
+ output = formatScanOutput(scanResults);
16
20
  }
17
21
  if (config.save !== undefined) {
18
22
  await saveScanFile(config, scanResults);
19
23
  }
24
+ if (config.fail) {
25
+ common.processFail(config, output);
26
+ }
20
27
  };
21
28
  module.exports = {
22
29
  processScan
@@ -12,19 +12,28 @@ const javascriptAnalysis = require('../../../scaAnalysis/javascript');
12
12
  const { pollForSnapshotCompletition } = require('../../../audit/languageAnalysisEngine/sendSnapshot');
13
13
  const { returnOra, startSpinner, succeedSpinner } = require('../../../utils/oraWrapper');
14
14
  const i18n = require('i18n');
15
- const { vulnerabilityReportV2 } = require('../../../audit/languageAnalysisEngine/report/reportingFeature');
15
+ const { vulnerabilityReportV2 } = require('../../../audit/report/reportingFeature');
16
16
  const auditSave = require('../../../audit/save');
17
17
  const { dotNetAnalysis } = require('../../../scaAnalysis/dotnet');
18
+ const { auditUsageGuide } = require('../../audit/help');
19
+ const rootFile = require('../../../audit/languageAnalysisEngine/getProjectRootFilenames');
20
+ const path = require('path');
18
21
  const processSca = async (config) => {
19
22
  const startTime = performance.now();
20
23
  let filesFound;
21
- if (config.file) {
22
- config.file = config.file.concat('/');
23
- filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config.file);
24
+ if (config.help) {
25
+ console.log(auditUsageGuide);
26
+ process.exit(0);
24
27
  }
25
- else {
26
- filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(undefined);
27
- config.file = process.cwd().concat('/');
28
+ const projectStats = await rootFile.getProjectStats(config.file);
29
+ let pathWithFile = projectStats.isFile();
30
+ config.fileName = config.file;
31
+ config.file = pathWithFile
32
+ ? rootFile.getDirectoryFromPathGiven(config.file).concat('/')
33
+ : config.file;
34
+ filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config.file);
35
+ if (filesFound.length > 1 && pathWithFile) {
36
+ filesFound = filesFound.filter(i => Object.values(i)[0].includes(path.basename(config.fileName)));
28
37
  }
29
38
  let messageToSend = undefined;
30
39
  if (filesFound.length === 1) {
@@ -45,7 +54,7 @@ const processSca = async (config) => {
45
54
  messageToSend = rubyAnalysis(config, filesFound[0]);
46
55
  config.language = RUBY;
47
56
  break;
48
- case 'PHP':
57
+ case PHP:
49
58
  messageToSend = phpAnalysis.phpAnalysis(config, filesFound[0]);
50
59
  config.language = PHP;
51
60
  break;
@@ -85,7 +94,9 @@ const processSca = async (config) => {
85
94
  throw new Error();
86
95
  }
87
96
  else {
88
- throw new Error('multiple language files detected, please use --file to specify a directory or the file where dependencies are declared');
97
+ throw new Error(`multiple language files detected \n` +
98
+ JSON.stringify(filesFound) +
99
+ `\nplease use --file to audit one language only. Example: contrast audit --file package-lock.json`);
89
100
  }
90
101
  }
91
102
  };
@@ -253,6 +253,12 @@ HTTPClient.prototype.getLatestVersion = function getLatestVersion() {
253
253
  'https://pkg.contrastsecurity.com/artifactory/cli/latest-version.txt';
254
254
  return requestUtils.sendRequest({ method: 'get', options });
255
255
  };
256
+ HTTPClient.prototype.postTelemetry = function postTelemetry(config, requestBody) {
257
+ const options = _.cloneDeep(this.requestOptions);
258
+ options.url = createTelemetryEventUrl(config);
259
+ options.body = requestBody;
260
+ return requestUtils.sendRequest({ method: 'post', options });
261
+ };
256
262
  HTTPClient.prototype.postAnalyticsFunction = function (config, provider, body) {
257
263
  const url = createAnalyticsFunctionPostUrl(config, provider);
258
264
  const options = { ...this.requestOptions, body, url };
@@ -319,6 +325,9 @@ function createDataUrl() {
319
325
  function createSbomUrl(config, type) {
320
326
  return `${config.host}/Contrast/api/ng/${config.organizationId}/applications/${config.applicationId}/libraries/sbom/${type}`;
321
327
  }
328
+ function createTelemetryEventUrl(config) {
329
+ return `${config.host}/Contrast/api/sast/organizations/${config.organizationId}/cli`;
330
+ }
322
331
  module.exports = HTTPClient;
323
332
  module.exports.pollForAuthUrl = pollForAuthUrl;
324
333
  module.exports.getServerlessHost = getServerlessHost;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.commonHelpLinks = void 0;
7
+ const i18n_1 = __importDefault(require("i18n"));
8
+ function commonHelpLinks() {
9
+ return {
10
+ header: i18n_1.default.__('commonHelpHeader'),
11
+ content: [
12
+ i18n_1.default.__('commonHelpCheckOutHeader') + i18n_1.default.__('commonHelpCheckOutText'),
13
+ i18n_1.default.__('commonHelpLearnMoreHeader') + i18n_1.default.__('commonHelpLearnMoreText'),
14
+ i18n_1.default.__('commonHelpJoinDiscussionHeader') +
15
+ i18n_1.default.__('commonHelpJoinDiscussionText')
16
+ ]
17
+ };
18
+ }
19
+ exports.commonHelpLinks = commonHelpLinks;
@@ -48,8 +48,8 @@ const reportFailureError = () => {
48
48
  };
49
49
  exports.reportFailureError = reportFailureError;
50
50
  const genericError = (missingCliOption) => {
51
- console.log(`*************************** ${i18n_1.default.__('yamlMissingParametersHeader')} ***************************\n${missingCliOption}`);
52
- console.error(i18n_1.default.__('yamlMissingParametersMessage'));
51
+ console.log(missingCliOption);
52
+ console.error(i18n_1.default.__('genericErrorMessage'));
53
53
  process.exit(1);
54
54
  };
55
55
  exports.genericError = genericError;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ const i18n = require('i18n');
3
+ const processFail = (config, reportResults) => {
4
+ if (config.severity !== undefined) {
5
+ if (reportResults[config.severity] !== undefined &&
6
+ isSeverityViolation(config.severity, reportResults)) {
7
+ failPipeline('failSeverityOptionErrorMessage');
8
+ }
9
+ }
10
+ if (config.severity === undefined && reportResults.total > 0) {
11
+ failPipeline('failThresholdOptionErrorMessage');
12
+ }
13
+ };
14
+ const isSeverityViolation = (severity, reportResults) => {
15
+ let count = 0;
16
+ switch (severity) {
17
+ case 'critical':
18
+ count += reportResults.critical;
19
+ break;
20
+ case 'high':
21
+ count += reportResults.high + reportResults.critical;
22
+ break;
23
+ case 'medium':
24
+ count += reportResults.medium + reportResults.low + reportResults.critical;
25
+ break;
26
+ case 'low':
27
+ count +=
28
+ reportResults.high + reportResults.critical + reportResults.medium;
29
+ break;
30
+ case 'note':
31
+ if (reportResults.note == reportResults.total) {
32
+ count = 0;
33
+ }
34
+ else {
35
+ count = reportResults.total;
36
+ }
37
+ break;
38
+ default:
39
+ count = 0;
40
+ }
41
+ return count > 0;
42
+ };
43
+ const failPipeline = (message = '') => {
44
+ console.log('\n ******************************** ' +
45
+ i18n.__('snapshotFailureHeader') +
46
+ ' *********************************\n' +
47
+ i18n.__(message));
48
+ process.exit(1);
49
+ };
50
+ const parseSeverity = severity => {
51
+ const severities = ['NOTE', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL'];
52
+ if (severities.includes(severity.toUpperCase())) {
53
+ return severity.toLowerCase();
54
+ }
55
+ else {
56
+ console.log(severity +
57
+ ' Not recognised as a severity type please use LOW, MEDIUM, HIGH, CRITICAL, NOTE');
58
+ return undefined;
59
+ }
60
+ };
61
+ module.exports = {
62
+ failPipeline,
63
+ processFail,
64
+ isSeverityViolation,
65
+ parseSeverity
66
+ };
@@ -23,8 +23,10 @@ const getLatestVersion = async (config) => {
23
23
  }
24
24
  };
25
25
  async function findLatestCLIVersion(config) {
26
- const messageHidden = config.get('updateMessageHidden');
27
- if (!messageHidden) {
26
+ const isCI = process.env.CONTRAST_CODESEC_CI
27
+ ? JSON.parse(process.env.CONTRAST_CODESEC_CI)
28
+ : false;
29
+ if (!isCI) {
28
30
  let latestCLIVersion = await getLatestVersion(config);
29
31
  latestCLIVersion = latestCLIVersion.substring(8);
30
32
  if (semver_1.default.lt(constants_1.APP_VERSION, latestCLIVersion)) {