@contrast/contrast 1.0.19 → 1.0.21

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 (66) hide show
  1. package/dist/audit/report/commonReportingFunctions.js +3 -4
  2. package/dist/audit/report/models/reportListModel.js +2 -1
  3. package/dist/audit/report/reportingFeature.js +1 -1
  4. package/dist/audit/report/utils/reportUtils.js +30 -11
  5. package/dist/cliConstants.js +13 -6
  6. package/dist/commands/audit/auditConfig.js +1 -2
  7. package/dist/commands/audit/help.js +2 -1
  8. package/dist/commands/audit/processAudit.js +1 -1
  9. package/dist/commands/fingerprint/fingerprintConfig.js +12 -0
  10. package/dist/commands/fingerprint/processFingerprint.js +14 -0
  11. package/dist/commands/learn/learn.js +9 -0
  12. package/dist/commands/learn/processLearn.js +10 -0
  13. package/dist/common/commonHelp.js +8 -1
  14. package/dist/constants/constants.js +1 -1
  15. package/dist/constants/locales.js +14 -3
  16. package/dist/index.js +8 -0
  17. package/dist/lambda/help.js +2 -1
  18. package/dist/scaAnalysis/common/auditReport.js +16 -60
  19. package/dist/scaAnalysis/common/commonReportingFunctionsSca.js +154 -0
  20. package/dist/scaAnalysis/common/models/ScaReportModel.js +45 -0
  21. package/dist/scaAnalysis/common/scaServicesUpload.js +4 -3
  22. package/dist/scaAnalysis/common/utils/reportUtilsSca.js +76 -0
  23. package/dist/scaAnalysis/java/analysis.js +1 -28
  24. package/dist/scaAnalysis/java/index.js +1 -13
  25. package/dist/scaAnalysis/scaAnalysis.js +155 -0
  26. package/dist/scan/autoDetection.js +2 -2
  27. package/dist/scan/fileUtils.js +2 -2
  28. package/dist/scan/formatScanOutput.js +19 -13
  29. package/dist/scan/help.js +2 -1
  30. package/dist/utils/paramsUtil/configStoreParams.js +1 -12
  31. package/dist/utils/paramsUtil/paramHandler.js +1 -7
  32. package/package.json +5 -1
  33. package/src/audit/report/commonReportingFunctions.js +7 -5
  34. package/src/audit/report/models/reportListModel.ts +12 -2
  35. package/src/audit/report/reportingFeature.ts +1 -1
  36. package/src/audit/report/utils/reportUtils.ts +4 -4
  37. package/src/cliConstants.js +15 -6
  38. package/src/commands/audit/auditConfig.js +1 -2
  39. package/src/commands/audit/help.js +2 -1
  40. package/src/commands/audit/processAudit.js +1 -1
  41. package/src/commands/fingerprint/fingerprintConfig.js +19 -0
  42. package/src/commands/fingerprint/processFingerprint.js +21 -0
  43. package/src/commands/learn/learn.js +10 -0
  44. package/src/commands/learn/processLearn.js +13 -0
  45. package/src/common/commonHelp.js +11 -1
  46. package/src/constants/constants.js +1 -1
  47. package/src/constants/locales.js +22 -3
  48. package/src/index.ts +11 -0
  49. package/src/lambda/help.ts +2 -1
  50. package/src/scaAnalysis/common/auditReport.js +25 -80
  51. package/src/scaAnalysis/common/commonReportingFunctionsSca.js +276 -0
  52. package/src/scaAnalysis/common/models/ScaReportModel.ts +81 -0
  53. package/src/scaAnalysis/common/scaServicesUpload.js +5 -3
  54. package/src/scaAnalysis/common/utils/reportUtilsSca.ts +123 -0
  55. package/src/scaAnalysis/java/analysis.js +1 -28
  56. package/src/scaAnalysis/java/index.js +1 -18
  57. package/src/scaAnalysis/scaAnalysis.js +206 -0
  58. package/src/scan/autoDetection.js +2 -2
  59. package/src/scan/fileUtils.js +2 -2
  60. package/src/scan/formatScanOutput.ts +28 -17
  61. package/src/scan/help.js +2 -1
  62. package/src/utils/getConfig.ts +0 -1
  63. package/src/utils/paramsUtil/configStoreParams.js +1 -14
  64. package/src/utils/paramsUtil/paramHandler.js +1 -9
  65. package/dist/commands/scan/sca/scaAnalysis.js +0 -155
  66. package/src/commands/scan/sca/scaAnalysis.js +0 -206
@@ -51,7 +51,7 @@ const printFormattedOutput = (config, libraries, numberOfVulnerableLibraries, nu
51
51
  const report = new ReportList();
52
52
  for (const library of libraries) {
53
53
  const { name, version } = findNameAndVersion(library, config);
54
- const newOutputModel = new ReportModelStructure(new ReportCompositeKey(name, version, findHighestSeverityCVE(library.cveArray), severityCountAllCVEs(library.cveArray, new SeverityCountModel()).getTotal), library.cveArray);
54
+ const newOutputModel = new ReportModelStructure(new ReportCompositeKey(name, version, findHighestSeverityCVE(library.cveArray), severityCountAllCVEs(library.cveArray, new SeverityCountModel()).getTotal), library.cveArray, null);
55
55
  report.reportOutputList.push(newOutputModel);
56
56
  }
57
57
  const outputOrderedByLowestSeverityAndLowestNumOfCvesFirst = orderBy(report.reportOutputList, [
@@ -120,8 +120,8 @@ function buildHeader(highestSeverity, contrastHeaderNum, libraryName, version, n
120
120
  return new ReportOutputHeaderModel(vulnMessage, introducesMessage);
121
121
  }
122
122
  function buildBody(cveArray, advice) {
123
- let assignPriorityToVulns = cveArray.map(result => findCVESeverity(result));
124
- const issueMessage = getIssueRow(assignPriorityToVulns);
123
+ const orderedCvesWithSeverityAssigned = orderByHighestPriority(cveArray.map(cve => findCVESeverity(cve)));
124
+ const issueMessage = getIssueRow(orderedCvesWithSeverityAssigned);
125
125
  const minOrMax = advice.maximum ? advice.maximum : advice.minimum;
126
126
  const displayAdvice = minOrMax
127
127
  ? `Change to version ${chalk.bold(minOrMax)}`
@@ -130,7 +130,6 @@ function buildBody(cveArray, advice) {
130
130
  return new ReportOutputBodyModel(issueMessage, adviceMessage);
131
131
  }
132
132
  function getIssueRow(cveArray) {
133
- orderByHighestPriority(cveArray);
134
133
  const cveMessagesList = getIssueCveMsgList(cveArray);
135
134
  return [chalk.bold('Issue'), ':', `${cveMessagesList.join(', ')}`];
136
135
  }
@@ -8,9 +8,10 @@ class ReportList {
8
8
  }
9
9
  exports.ReportList = ReportList;
10
10
  class ReportModelStructure {
11
- constructor(compositeKey, cveArray) {
11
+ constructor(compositeKey, cveArray, remediationAdvice) {
12
12
  this.compositeKey = compositeKey;
13
13
  this.cveArray = cveArray;
14
+ this.remediationAdvice = remediationAdvice;
14
15
  }
15
16
  }
16
17
  exports.ReportModelStructure = ReportModelStructure;
@@ -80,7 +80,7 @@ async function vulnerabilityReportV2(config, reportId) {
80
80
  console.log();
81
81
  const reportResponse = await (0, commonReportingFunctions_1.getReport)(config, reportId);
82
82
  if (reportResponse !== undefined) {
83
- let output = formatVulnerabilityOutput(reportResponse.vulnerabilities, config.applicationId, config, reportResponse.remediationGuidance
83
+ const output = formatVulnerabilityOutput(reportResponse.vulnerabilities, config.applicationId, config, reportResponse.remediationGuidance
84
84
  ? reportResponse.remediationGuidance
85
85
  : {});
86
86
  if (config.fail) {
@@ -1,13 +1,32 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
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;
4
24
  };
5
25
  Object.defineProperty(exports, "__esModule", { value: true });
6
26
  exports.countVulnerableLibrariesBySeverity = exports.findNameAndVersion = exports.severityCountSingleCVE = exports.severityCountAllCVEs = exports.severityCountAllLibraries = exports.convertGenericToTypedLibraryVulns = exports.findCVESeverity = exports.orderByHighestPriority = exports.findHighestSeverityCVE = void 0;
7
27
  const reportLibraryModel_1 = require("../models/reportLibraryModel");
8
28
  const reportSeverityModel_1 = require("../models/reportSeverityModel");
9
- const constants_1 = __importDefault(require("../../../constants/constants"));
10
- const constants_2 = require("../../../constants/constants");
29
+ const constants_1 = __importStar(require("../../../constants/constants"));
11
30
  const lodash_1 = require("lodash");
12
31
  const severityCountModel_1 = require("../models/severityCountModel");
13
32
  const { supportedLanguages: { GO } } = constants_1.default;
@@ -16,27 +35,27 @@ function findHighestSeverityCVE(cveArray) {
16
35
  return (0, lodash_1.orderBy)(mappedToReportSeverityModels, cve => cve?.priority)[0];
17
36
  }
18
37
  exports.findHighestSeverityCVE = findHighestSeverityCVE;
19
- function orderByHighestPriority(cves) {
20
- return (0, lodash_1.orderBy)(cves, ['priority'], ['asc']);
38
+ function orderByHighestPriority(severityModels) {
39
+ return (0, lodash_1.orderBy)(severityModels, ['priority'], ['asc']);
21
40
  }
22
41
  exports.orderByHighestPriority = orderByHighestPriority;
23
42
  function findCVESeverity(cve) {
24
43
  const cveName = cve.name;
25
44
  if (cve.cvss3SeverityCode === 'CRITICAL' || cve.severityCode === 'CRITICAL') {
26
- return new reportSeverityModel_1.ReportSeverityModel('CRITICAL', constants_2.CRITICAL_PRIORITY, constants_2.CRITICAL_COLOUR, cveName);
45
+ return new reportSeverityModel_1.ReportSeverityModel('CRITICAL', constants_1.CRITICAL_PRIORITY, constants_1.CRITICAL_COLOUR, cveName);
27
46
  }
28
47
  else if (cve.cvss3SeverityCode === 'HIGH' || cve.severityCode === 'HIGH') {
29
- return new reportSeverityModel_1.ReportSeverityModel('HIGH', constants_2.HIGH_PRIORITY, constants_2.HIGH_COLOUR, cveName);
48
+ return new reportSeverityModel_1.ReportSeverityModel('HIGH', constants_1.HIGH_PRIORITY, constants_1.HIGH_COLOUR, cveName);
30
49
  }
31
50
  else if (cve.cvss3SeverityCode === 'MEDIUM' ||
32
51
  cve.severityCode === 'MEDIUM') {
33
- return new reportSeverityModel_1.ReportSeverityModel('MEDIUM', constants_2.MEDIUM_PRIORITY, constants_2.MEDIUM_COLOUR, cveName);
52
+ return new reportSeverityModel_1.ReportSeverityModel('MEDIUM', constants_1.MEDIUM_PRIORITY, constants_1.MEDIUM_COLOUR, cveName);
34
53
  }
35
54
  else if (cve.cvss3SeverityCode === 'LOW' || cve.severityCode === 'LOW') {
36
- return new reportSeverityModel_1.ReportSeverityModel('LOW', constants_2.LOW_PRIORITY, constants_2.LOW_COLOUR, cveName);
55
+ return new reportSeverityModel_1.ReportSeverityModel('LOW', constants_1.LOW_PRIORITY, constants_1.LOW_COLOUR, cveName);
37
56
  }
38
57
  else if (cve.cvss3SeverityCode === 'NOTE' || cve.severityCode === 'NOTE') {
39
- return new reportSeverityModel_1.ReportSeverityModel('NOTE', constants_2.NOTE_PRIORITY, constants_2.NOTE_COLOUR, cveName);
58
+ return new reportSeverityModel_1.ReportSeverityModel('NOTE', constants_1.NOTE_PRIORITY, constants_1.NOTE_COLOUR, cveName);
40
59
  }
41
60
  }
42
61
  exports.findCVESeverity = findCVESeverity;
@@ -296,10 +296,6 @@ const auditOptionDefinitions = [
296
296
  '}: ' +
297
297
  i18n.__('constantsIgnoreDev')
298
298
  },
299
- {
300
- name: 'fingerprint',
301
- type: Boolean
302
- },
303
299
  {
304
300
  name: 'save',
305
301
  alias: 's',
@@ -358,6 +354,14 @@ const auditOptionDefinitions = [
358
354
  i18n.__('auditOptionsBranchSummary')
359
355
  }
360
356
  ];
357
+ const fingerprintOptionDefinitions = [
358
+ ...auditOptionDefinitions,
359
+ {
360
+ name: 'depth',
361
+ type: Number,
362
+ description: '{bold ' + i18n.__('constantsOptional') + '}: ' + i18n.__('depthOption')
363
+ }
364
+ ];
361
365
  const mainUsageGuide = commandLineUsage([
362
366
  {
363
367
  header: i18n.__('constantsHeader'),
@@ -379,7 +383,8 @@ const mainUsageGuide = commandLineUsage([
379
383
  { name: i18n.__('auditName'), summary: i18n.__('helpAuditSummary') },
380
384
  { name: i18n.__('versionName'), summary: i18n.__('helpVersionSummary') },
381
385
  { name: i18n.__('configName'), summary: i18n.__('helpConfigSummary') },
382
- { name: i18n.__('helpName'), summary: i18n.__('helpSummary') }
386
+ { name: i18n.__('helpName'), summary: i18n.__('helpSummary') },
387
+ { name: i18n.__('learnName'), summary: i18n.__('helpLearnSummary') }
383
388
  ]
384
389
  },
385
390
  {
@@ -393,7 +398,8 @@ const mainUsageGuide = commandLineUsage([
393
398
  ]
394
399
  },
395
400
  commonHelpLinks()[0],
396
- commonHelpLinks()[1]
401
+ commonHelpLinks()[1],
402
+ commonHelpLinks()[2]
397
403
  ]);
398
404
  const mainDefinition = [{ name: 'command', defaultOption: true }];
399
405
  module.exports = {
@@ -401,6 +407,7 @@ module.exports = {
401
407
  mainUsageGuide,
402
408
  mainDefinition,
403
409
  scanOptionDefinitions,
410
+ fingerprintOptionDefinitions,
404
411
  auditOptionDefinitions,
405
412
  authOptionDefinitions,
406
413
  configOptionDefinitions,
@@ -5,8 +5,7 @@ const paramHandler = require('../../utils/paramsUtil/paramHandler');
5
5
  const getAuditConfig = async (contrastConf, command, argv) => {
6
6
  const auditParameters = await getCommandLineArgsCustom(contrastConf, command, argv, constants.commandLineDefinitions.auditOptionDefinitions);
7
7
  const paramsAuth = paramHandler.getAuth(auditParameters);
8
- const javaAgreement = paramHandler.getAgreement();
9
- return { ...paramsAuth, ...auditParameters, ...javaAgreement };
8
+ return { ...paramsAuth, ...auditParameters };
10
9
  };
11
10
  module.exports = {
12
11
  getAuditConfig
@@ -61,7 +61,8 @@ const auditUsageGuide = commandLineUsage([
61
61
  optionList: constants.commandLineDefinitions.auditAdvancedOptionDefinitionsForHelp
62
62
  },
63
63
  commonHelpLinks()[0],
64
- commonHelpLinks()[1]
64
+ commonHelpLinks()[1],
65
+ commonHelpLinks()[2]
65
66
  ]);
66
67
  module.exports = {
67
68
  auditUsageGuide
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  const auditConfig = require('./auditConfig');
3
3
  const { auditUsageGuide } = require('./help');
4
- const scaController = require('../scan/sca/scaAnalysis');
4
+ const scaController = require('../../scaAnalysis/scaAnalysis');
5
5
  const { sendTelemetryConfigAsObject } = require('../../telemetry/telemetry');
6
6
  const { postRunMessage } = require('../../common/commonHelp');
7
7
  const processAudit = async (contrastConf, argvMain) => {
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ const parsedCLIOptions = require('../../utils/parsedCLIOptions');
3
+ const constants = require('../../cliConstants');
4
+ const paramHandler = require('../../utils/paramsUtil/paramHandler');
5
+ const getFingerprintConfig = async (contrastConf, command, argv) => {
6
+ const fingerprintParameters = await parsedCLIOptions.getCommandLineArgsCustom(contrastConf, command, argv, constants.commandLineDefinitions.fingerprintOptionDefinitions);
7
+ const paramsAuth = paramHandler.getAuth(fingerprintParameters);
8
+ return { ...paramsAuth, ...fingerprintParameters };
9
+ };
10
+ module.exports = {
11
+ getFingerprintConfig
12
+ };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ const fingerprintConfig = require('./fingerprintConfig');
3
+ const autoDetection = require('../../scan/autoDetection');
4
+ const saveResults = require('../../scan/saveResults');
5
+ const processFingerprint = async (contrastConf, argvMain) => {
6
+ const config = await fingerprintConfig.getFingerprintConfig(contrastConf, 'fingerprint', argvMain);
7
+ let fingerprint = await autoDetection.autoDetectFingerprintInfo(config.file, config.depth);
8
+ let idArray = fingerprint.map(x => x.id);
9
+ await saveResults.writeResultsToFile(fingerprint, 'fingerPrintInfo.json');
10
+ return console.log(idArray);
11
+ };
12
+ module.exports = {
13
+ processFingerprint
14
+ };
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ const open = require('open');
3
+ async function openLearnPage() {
4
+ const url = 'https://www.contrastsecurity.com/developer/learn';
5
+ return open(url);
6
+ }
7
+ module.exports = {
8
+ openLearnPage
9
+ };
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ const { openLearnPage } = require('./learn');
3
+ async function processLearn() {
4
+ console.log('Opening develop central...');
5
+ console.log('If the page does not open you can open it directly via https://www.contrastsecurity.com/developer/learn');
6
+ return openLearnPage();
7
+ }
8
+ module.exports = {
9
+ processLearn
10
+ };
@@ -19,17 +19,24 @@ const commonHelpLinks = () => {
19
19
  i18n.__('commonHelpLearnMoreEnterpriseHeader') +
20
20
  i18n.__('commonHelpLearnMoreEnterpriseText')
21
21
  ]
22
+ },
23
+ {
24
+ content: [
25
+ i18n.__('commonHelpLearnHeader') + i18n.__('commonHelpLearnText')
26
+ ]
22
27
  }
23
28
  ];
24
29
  };
25
30
  const postRunMessage = commandName => {
26
31
  console.log('\n' + chalk.underline.bold('Other Features:'));
27
32
  if (commandName !== 'scan')
28
- console.log("'contrast scan' to run Contrasts’ industry leading SAST scanner");
33
+ console.log("'contrast scan' to run Contrast's industry leading SAST scanner");
29
34
  if (commandName !== 'audit')
30
35
  console.log("'contrast audit' to find vulnerabilities in your open source dependencies");
31
36
  if (commandName !== 'lambda')
32
37
  console.log("'contrast lambda' to secure your AWS serverless functions");
38
+ if (commandName !== 'learn')
39
+ console.log("'contrast learn' launches Contrast's Secure Code Learning Hub.");
33
40
  };
34
41
  module.exports = {
35
42
  commonHelpLinks,
@@ -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.19';
15
+ const APP_VERSION = '1.0.21';
16
16
  const TIMEOUT = 120000;
17
17
  const HIGH_COLOUR = '#ff9900';
18
18
  const CRITICAL_COLOUR = '#e35858';
@@ -121,6 +121,10 @@ const en_locales = () => {
121
121
  versionName: 'version',
122
122
  configName: 'config',
123
123
  helpName: 'help',
124
+ learnName: 'learn',
125
+ helpLearnSummary: 'launches Contrast’s Secure Code Learning Hub.',
126
+ fingerprintName: 'assess repo to see how many languages it can detect. For use in pipeline only.',
127
+ depthOption: 'can set how deep in the file system the cli looks for language files',
124
128
  scanOptionsLanguageSummary: 'Valid values are JAVA, JAVASCRIPT and DOTNET',
125
129
  scanOptionsTimeoutSummary: 'Time in seconds to wait for scan to complete. Default value is 300 seconds.',
126
130
  scanOptionsFileNameSummary: 'Path of the file you want to scan. If no file is specified, Contrast searches for a .jar, .war, .exe or .zip file in the working directory.',
@@ -134,7 +138,10 @@ const en_locales = () => {
134
138
  chalk.bold('\ncontrast scan') +
135
139
  " to run Contrast's industry leading SAST scanner. \nSupports Java, JavaScript and .Net \n" +
136
140
  chalk.bold('\ncontrast audit') +
137
- ' to find vulnerabilities in your open source dependencies.\nSupports Java, .NET, Node, Ruby, Python, Go and PHP \n' +
141
+ ' to find vulnerabilities in your open source dependencies.' +
142
+ '\nSupports Java, .NET, Node, Ruby, Python, Go and PHP.' +
143
+ '\nOur CLI runs native build tools to generate a complete dependency tree.' +
144
+ '\nIf you are running on untrusted code, consider running in a sandbox.\n' +
138
145
  chalk.bold('\ncontrast lambda') +
139
146
  ' to secure your AWS serverless functions. \nSupports Java and Python \n' +
140
147
  chalk.bold('\ncontrast help') +
@@ -181,7 +188,8 @@ const en_locales = () => {
181
188
  constantsAuditPrerequisitesContentSupportedLanguages: 'Supported languages and their requirements are:',
182
189
  constantsAuditPrerequisitesJavaContentMessage: `
183
190
  ${chalk.bold('Java:')} pom.xml ${chalk.bold('and')} Maven build platform including the dependency plugin.
184
- ${chalk.bold('Or')} build.gradle ${chalk.bold('and')} gradle dependencies or ./gradlew dependencies must be supported`,
191
+ ${chalk.bold('Or')} build.gradle ${chalk.bold('and')} gradle dependencies or ./gradlew dependencies must be supported
192
+ If you are running on untrusted code, consider running in a sandbox.`,
185
193
  constantsAuditPrerequisitesContentDotNetMessage: `
186
194
  ${chalk.bold('.NET framework and .NET core:')} MSBuild 15.0 or greater and a packages.lock.json file.
187
195
  Note: If the packages.lock.json file is unavailable it can be generated by setting RestorePackagesWithLockFile to true within each *.csproj file and running dotnet build.\n`,
@@ -215,7 +223,10 @@ const en_locales = () => {
215
223
  commonHelpLearnMoreText: ' https://www.contrastsecurity.com/developer ',
216
224
  commonHelpLearnMoreEnterpriseText: ' https://docs.contrastsecurity.com/en/run-contrast-cli.html ',
217
225
  commonHelpJoinDiscussionHeader: chalk.hex('#9DC184')('Join the discussion:'),
218
- commonHelpJoinDiscussionText: ' https://dev.to/codesec',
226
+ commonHelpJoinDiscussionText: ' https://www.contrastsecurity.com/developer/community',
227
+ commonHelpLearnHeader: chalk.hex('#ffe599')('\rWant to UP your game?') +
228
+ " type 'contrast learn'",
229
+ commonHelpLearnText: `\n🎓 Advance your security knowledge and become an ${chalk.hex('#ffd966')('All-star coder')} ⭐ with ${chalk.bold('Contrast Secure Code Learning Hub.')} 😺`,
219
230
  authCommand: {
220
231
  credentialsAccepted: {
221
232
  title: 'Credentials accepted',
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ const processAudit_1 = require("./commands/audit/processAudit");
9
9
  const auth_1 = require("./commands/auth/auth");
10
10
  const config_1 = require("./commands/config/config");
11
11
  const processScan_1 = require("./commands/scan/processScan");
12
+ const processFingerprint_1 = require("./commands/fingerprint/processFingerprint");
12
13
  const cliConstants_1 = __importDefault(require("./cliConstants"));
13
14
  const constants_1 = require("./constants/constants");
14
15
  const lambda_1 = require("./lambda/lambda");
@@ -16,6 +17,7 @@ const getConfig_1 = require("./utils/getConfig");
16
17
  const versionChecker_1 = require("./common/versionChecker");
17
18
  const errorHandling_1 = require("./common/errorHandling");
18
19
  const telemetry_1 = require("./telemetry/telemetry");
20
+ const processLearn_1 = require("./commands/learn/processLearn");
19
21
  const { commandLineDefinitions: { mainUsageGuide, mainDefinition } } = cliConstants_1.default;
20
22
  const config = (0, getConfig_1.localConfig)(constants_1.APP_NAME, constants_1.APP_VERSION);
21
23
  const getMainOption = () => {
@@ -64,6 +66,12 @@ const start = async () => {
64
66
  if (command === 'audit') {
65
67
  return await (0, processAudit_1.processAudit)(config, argvMain);
66
68
  }
69
+ if (command === 'learn') {
70
+ return (0, processLearn_1.processLearn)();
71
+ }
72
+ if (command === 'fingerprint') {
73
+ return await (0, processFingerprint_1.processFingerprint)(config, argvMain);
74
+ }
67
75
  if (command === 'help' ||
68
76
  argvMain.includes('--help') ||
69
77
  Object.keys(mainOptions).length === 0) {
@@ -82,6 +82,7 @@ const lambdaUsageGuide = (0, command_line_usage_1.default)([
82
82
  ]
83
83
  },
84
84
  (0, commonHelp_1.commonHelpLinks)()[0],
85
- (0, commonHelp_1.commonHelpLinks)()[1]
85
+ (0, commonHelp_1.commonHelpLinks)()[1],
86
+ (0, commonHelp_1.commonHelpLinks)()[2]
86
87
  ]);
87
88
  exports.lambdaUsageGuide = lambdaUsageGuide;
@@ -1,77 +1,33 @@
1
1
  "use strict";
2
- const { getSeverityCounts, createSummaryMessageTop, printVulnInfo, getReportTable, getIssueRow, printNoVulnFoundMsg } = require('../../audit/report/commonReportingFunctions');
3
- const { orderBy } = require('lodash');
4
- const { assignBySeverity } = require('../../scan/formatScanOutput');
5
- const chalk = require('chalk');
6
- const { CE_URL } = require('../../constants/constants');
2
+ const { getSeverityCounts, printNoVulnFoundMsg } = require('../../audit/report/commonReportingFunctions');
7
3
  const common = require('../../common/fail');
8
- const i18n = require('i18n');
9
- const processAuditReport = (config, results) => {
4
+ const { printFormattedOutputSca } = require('./commonReportingFunctionsSca');
5
+ const processAuditReport = (config, reportModelList) => {
10
6
  let severityCounts = {};
11
- if (results !== undefined) {
12
- severityCounts = formatScaServicesReport(config, results);
7
+ if (reportModelList !== undefined) {
8
+ severityCounts = formatScaServicesReport(config, reportModelList);
13
9
  }
14
10
  if (config.fail) {
15
11
  common.processFail(config, severityCounts);
16
12
  }
17
13
  };
18
- const formatScaServicesReport = (config, results) => {
19
- const projectOverviewCount = getSeverityCounts(results);
14
+ const formatScaServicesReport = (config, reportModelList) => {
15
+ const projectOverviewCount = getSeverityCounts(reportModelList);
20
16
  if (projectOverviewCount.total === 0) {
21
17
  printNoVulnFoundMsg();
22
- return projectOverviewCount;
23
18
  }
24
19
  else {
25
- let total = 0;
26
- const numberOfCves = results.length;
27
- const table = getReportTable();
28
- let contrastHeaderNumCounter = 0;
29
- let assignPriorityToResults = results.map(result => assignBySeverity(result, result));
30
- const numberOfVulns = results
31
- .map(result => result.vulnerabilities)
32
- .reduce((a, b) => {
33
- return (total += b.length);
34
- }, 0);
35
- const outputOrderedByLowestSeverityAndLowestNumOfCvesFirst = orderBy(assignPriorityToResults, [
36
- reportListItem => {
37
- return reportListItem.priority;
38
- },
39
- reportListItem => {
40
- return reportListItem.vulnerabilities.length;
20
+ const numberOfVulnerableLibraries = reportModelList.map(library => {
21
+ let count = 0;
22
+ if (library.vulnerabilities.length > 0) {
23
+ count++;
41
24
  }
42
- ], ['asc', 'desc']);
43
- for (const result of outputOrderedByLowestSeverityAndLowestNumOfCvesFirst) {
44
- contrastHeaderNumCounter++;
45
- const cvesNum = result.vulnerabilities.length;
46
- const grammaticallyCorrectVul = result.vulnerabilities.length > 1 ? 'vulnerabilities' : 'vulnerability';
47
- const headerColour = chalk.hex(result.colour);
48
- const headerRow = [
49
- headerColour(`CONTRAST-${contrastHeaderNumCounter.toString().padStart(3, '0')}`),
50
- headerColour(`-`),
51
- headerColour(`[${result.severity}] `) +
52
- headerColour.bold(`${result.artifactName}`) +
53
- ` introduces ${cvesNum} ${grammaticallyCorrectVul}`
54
- ];
55
- const adviceRow = [
56
- chalk.bold(`Advice`),
57
- chalk.bold(`:`),
58
- `Change to version ${result.remediationAdvice.latestStableVersion}`
59
- ];
60
- let assignPriorityToVulns = result.vulnerabilities.map(result => assignBySeverity(result, result));
61
- const issueRow = getIssueRow(assignPriorityToVulns);
62
- table.push(headerRow, issueRow, adviceRow);
63
- console.log();
64
- }
65
- console.log();
66
- createSummaryMessageTop(numberOfCves, numberOfVulns);
67
- console.log(table.toString() + '\n');
68
- printVulnInfo(projectOverviewCount);
69
- if (config.host !== CE_URL) {
70
- console.log('\n' + chalk.bold(i18n.__('auditServicesMessageForTS')));
71
- console.log(`${config.host}/Contrast/static/ng/index.html#/${config.organizationId}/applications/${config.applicationId}/libs`);
72
- }
73
- return projectOverviewCount;
25
+ return count;
26
+ }).length;
27
+ let numberOfCves = reportModelList.reduce((count, current) => count + current.vulnerabilities.length, 0);
28
+ printFormattedOutputSca(config, reportModelList, numberOfVulnerableLibraries, numberOfCves);
74
29
  }
30
+ return projectOverviewCount;
75
31
  };
76
32
  module.exports = {
77
33
  formatScaServicesReport,
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ const { ReportList, ReportModelStructure, ReportCompositeKey } = require('../../audit/report/models/reportListModel');
3
+ const { countVulnerableLibrariesBySeverity } = require('../../audit/report/utils/reportUtils');
4
+ const { SeverityCountModel } = require('../../audit/report/models/severityCountModel');
5
+ const { orderBy } = require('lodash');
6
+ const { ReportOutputModel, ReportOutputHeaderModel, ReportOutputBodyModel } = require('../../audit/report/models/reportOutputModel');
7
+ const { CE_URL, CRITICAL_COLOUR, HIGH_COLOUR, MEDIUM_COLOUR, LOW_COLOUR, NOTE_COLOUR } = require('../../constants/constants');
8
+ const chalk = require('chalk');
9
+ const Table = require('cli-table3');
10
+ const { findHighestSeverityCVESca, severityCountAllCVEsSca, findCVESeveritySca, orderByHighestPrioritySca } = require('./utils/reportUtilsSca');
11
+ const { buildFormattedHeaderNum } = require('../../audit/report/commonReportingFunctions');
12
+ const createSummaryMessageTop = (numberOfVulnerableLibraries, numberOfCves) => {
13
+ numberOfVulnerableLibraries === 1
14
+ ? console.log(`\n\nFound 1 vulnerable library containing ${numberOfCves} CVE`)
15
+ : console.log(`\n\nFound ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVEs`);
16
+ };
17
+ const createSummaryMessageBottom = numberOfVulnerableLibraries => {
18
+ numberOfVulnerableLibraries === 1
19
+ ? console.log(`Found 1 vulnerability`)
20
+ : console.log(`Found ${numberOfVulnerableLibraries} vulnerabilities`);
21
+ };
22
+ const printFormattedOutputSca = (config, reportModelList, numberOfVulnerableLibraries, numberOfCves) => {
23
+ createSummaryMessageTop(numberOfVulnerableLibraries, numberOfCves);
24
+ console.log();
25
+ const report = new ReportList();
26
+ for (const library of reportModelList) {
27
+ const { artifactName, version, vulnerabilities, remediationAdvice } = library;
28
+ const newOutputModel = new ReportModelStructure(new ReportCompositeKey(artifactName, version, findHighestSeverityCVESca(vulnerabilities), severityCountAllCVEsSca(vulnerabilities, new SeverityCountModel()).getTotal), vulnerabilities, remediationAdvice);
29
+ report.reportOutputList.push(newOutputModel);
30
+ }
31
+ const outputOrderedByLowestSeverityAndLowestNumOfCvesFirst = orderBy(report.reportOutputList, [
32
+ reportListItem => {
33
+ return reportListItem.compositeKey.highestSeverity.priority;
34
+ },
35
+ reportListItem => {
36
+ return reportListItem.compositeKey.numberOfSeverities;
37
+ }
38
+ ], ['asc', 'desc']);
39
+ let contrastHeaderNumCounter = 0;
40
+ for (const reportModel of outputOrderedByLowestSeverityAndLowestNumOfCvesFirst) {
41
+ contrastHeaderNumCounter++;
42
+ const { libraryName, libraryVersion, highestSeverity } = reportModel.compositeKey;
43
+ const { cveArray, remediationAdvice } = reportModel;
44
+ const numOfCVEs = reportModel.cveArray.length;
45
+ const table = getReportTable();
46
+ const header = buildHeader(highestSeverity, contrastHeaderNumCounter, libraryName, libraryVersion, numOfCVEs);
47
+ const body = buildBody(cveArray, remediationAdvice);
48
+ const reportOutputModel = new ReportOutputModel(header, body);
49
+ table.push(reportOutputModel.body.issueMessage, reportOutputModel.body.adviceMessage);
50
+ console.log(reportOutputModel.header.vulnMessage, reportOutputModel.header.introducesMessage);
51
+ console.log(table.toString() + '\n');
52
+ }
53
+ createSummaryMessageBottom(numberOfVulnerableLibraries);
54
+ const { criticalMessage, highMessage, mediumMessage, lowMessage, noteMessage } = buildFooter(outputOrderedByLowestSeverityAndLowestNumOfCvesFirst);
55
+ console.log(`${criticalMessage} | ${highMessage} | ${mediumMessage} | ${lowMessage} | ${noteMessage}`);
56
+ if (config.host !== CE_URL) {
57
+ console.log('\n' + chalk.bold('View your full dependency tree in Contrast:'));
58
+ console.log(`${config.host}/Contrast/static/ng/index.html#/${config.organizationId}/applications/${config.applicationId}/libs/dependency-tree`);
59
+ }
60
+ };
61
+ function getReportTable() {
62
+ return new Table({
63
+ chars: {
64
+ top: '',
65
+ 'top-mid': '',
66
+ 'top-left': '',
67
+ 'top-right': '',
68
+ bottom: '',
69
+ 'bottom-mid': '',
70
+ 'bottom-left': '',
71
+ 'bottom-right': '',
72
+ left: '',
73
+ 'left-mid': '',
74
+ mid: '',
75
+ 'mid-mid': '',
76
+ right: '',
77
+ 'right-mid': '',
78
+ middle: ' '
79
+ },
80
+ style: { 'padding-left': 0, 'padding-right': 0 },
81
+ colAligns: ['right'],
82
+ wordWrap: true,
83
+ colWidths: [12, 1, 100]
84
+ });
85
+ }
86
+ function buildHeader(highestSeverity, contrastHeaderNum, libraryName, version, numOfCVEs) {
87
+ const vulnerabilityPluralised = numOfCVEs > 1 ? 'vulnerabilities' : 'vulnerability';
88
+ const formattedHeaderNum = buildFormattedHeaderNum(contrastHeaderNum);
89
+ const headerColour = chalk.hex(highestSeverity.colour);
90
+ const headerNumAndSeverity = headerColour(`${formattedHeaderNum} - [${highestSeverity.severity}]`);
91
+ const libraryNameAndVersion = headerColour.bold(`${libraryName}-${version}`);
92
+ const vulnMessage = `${headerNumAndSeverity} ${libraryNameAndVersion}`;
93
+ const introducesMessage = `introduces ${numOfCVEs} ${vulnerabilityPluralised}`;
94
+ return new ReportOutputHeaderModel(vulnMessage, introducesMessage);
95
+ }
96
+ function buildBody(cveArray, advice) {
97
+ const orderedCvesWithSeverityAssigned = orderByHighestPrioritySca(cveArray.map(cve => findCVESeveritySca(cve)));
98
+ const issueMessage = getIssueRow(orderedCvesWithSeverityAssigned);
99
+ const adviceMessage = getAdviceRow(advice);
100
+ return new ReportOutputBodyModel(issueMessage, adviceMessage);
101
+ }
102
+ function getIssueRow(cveArray) {
103
+ const cveMessagesList = getIssueCveMsgList(cveArray);
104
+ return [chalk.bold('Issue'), ':', `${cveMessagesList.join(', ')}`];
105
+ }
106
+ function getAdviceRow(advice) {
107
+ const latestOrClosest = advice.latestStableVersion
108
+ ? advice.latestStableVersion
109
+ : advice.closestStableVersion;
110
+ const displayAdvice = latestOrClosest
111
+ ? `Change to version ${chalk.bold(latestOrClosest)}`
112
+ : 'No recommendation is available according to our data. Upgrade to the latest stable is the best advice we can give.';
113
+ return [chalk.bold(`Advice`), chalk.bold(`:`), `${displayAdvice}`];
114
+ }
115
+ const buildFooter = reportModelStructure => {
116
+ const { critical, high, medium, low, note } = countVulnerableLibrariesBySeverity(reportModelStructure);
117
+ const criticalMessage = chalk
118
+ .hex(CRITICAL_COLOUR)
119
+ .bold(`${critical} Critical`);
120
+ const highMessage = chalk.hex(HIGH_COLOUR).bold(`${high} High`);
121
+ const mediumMessage = chalk.hex(MEDIUM_COLOUR).bold(`${medium} Medium`);
122
+ const lowMessage = chalk.hex(LOW_COLOUR).bold(`${low} Low`);
123
+ const noteMessage = chalk.hex(NOTE_COLOUR).bold(`${note} Note`);
124
+ return {
125
+ criticalMessage,
126
+ highMessage,
127
+ mediumMessage,
128
+ lowMessage,
129
+ noteMessage
130
+ };
131
+ };
132
+ const getIssueCveMsgList = reportSeverityModels => {
133
+ const cveMessages = [];
134
+ reportSeverityModels.forEach(reportSeverityModel => {
135
+ const { colour, severity, name } = reportSeverityModel;
136
+ const severityShorthand = chalk
137
+ .hex(colour)
138
+ .bold(`[${severity.charAt(0).toUpperCase()}]`);
139
+ const builtMessage = severityShorthand + name;
140
+ cveMessages.push(builtMessage);
141
+ });
142
+ return cveMessages;
143
+ };
144
+ module.exports = {
145
+ createSummaryMessageTop,
146
+ createSummaryMessageBottom,
147
+ printFormattedOutputSca,
148
+ getReportTable,
149
+ buildHeader,
150
+ buildBody,
151
+ getIssueRow,
152
+ buildFormattedHeaderNum,
153
+ getIssueCveMsgList
154
+ };