@contrast/contrast 1.0.19 → 1.0.20

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 (38) 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/commands/audit/auditConfig.js +1 -2
  6. package/dist/commands/scan/sca/scaAnalysis.js +4 -2
  7. package/dist/constants/constants.js +1 -1
  8. package/dist/constants/locales.js +6 -2
  9. package/dist/scaAnalysis/common/auditReport.js +16 -60
  10. package/dist/scaAnalysis/common/commonReportingFunctionsSca.js +154 -0
  11. package/dist/scaAnalysis/common/models/ScaReportModel.js +45 -0
  12. package/dist/scaAnalysis/common/scaServicesUpload.js +4 -3
  13. package/dist/scaAnalysis/common/utils/reportUtilsSca.js +76 -0
  14. package/dist/scaAnalysis/java/analysis.js +1 -28
  15. package/dist/scaAnalysis/java/index.js +1 -13
  16. package/dist/scan/formatScanOutput.js +19 -13
  17. package/dist/utils/paramsUtil/configStoreParams.js +1 -12
  18. package/dist/utils/paramsUtil/paramHandler.js +1 -7
  19. package/package.json +5 -1
  20. package/src/audit/report/commonReportingFunctions.js +7 -5
  21. package/src/audit/report/models/reportListModel.ts +12 -2
  22. package/src/audit/report/reportingFeature.ts +1 -1
  23. package/src/audit/report/utils/reportUtils.ts +4 -4
  24. package/src/commands/audit/auditConfig.js +1 -2
  25. package/src/commands/scan/sca/scaAnalysis.js +7 -2
  26. package/src/constants/constants.js +1 -1
  27. package/src/constants/locales.js +6 -2
  28. package/src/scaAnalysis/common/auditReport.js +25 -80
  29. package/src/scaAnalysis/common/commonReportingFunctionsSca.js +276 -0
  30. package/src/scaAnalysis/common/models/ScaReportModel.ts +81 -0
  31. package/src/scaAnalysis/common/scaServicesUpload.js +5 -3
  32. package/src/scaAnalysis/common/utils/reportUtilsSca.ts +123 -0
  33. package/src/scaAnalysis/java/analysis.js +1 -28
  34. package/src/scaAnalysis/java/index.js +1 -18
  35. package/src/scan/formatScanOutput.ts +28 -17
  36. package/src/utils/getConfig.ts +0 -1
  37. package/src/utils/paramsUtil/configStoreParams.js +1 -14
  38. package/src/utils/paramsUtil/paramHandler.js +1 -9
@@ -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;
@@ -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
@@ -24,6 +24,7 @@ const scaUpload = require('../../../scaAnalysis/common/scaServicesUpload');
24
24
  const settingsHelper = require('../../../utils/settingsHelper');
25
25
  const chalk = require('chalk');
26
26
  const saveResults = require('../../../scan/saveResults');
27
+ const { convertGenericToTypedReportModelSca } = require('../../../scaAnalysis/common/utils/reportUtilsSca');
27
28
  const processSca = async (config) => {
28
29
  config = await settingsHelper.getSettings(config);
29
30
  const startTime = performance.now();
@@ -102,8 +103,9 @@ const processSca = async (config) => {
102
103
  console.log('');
103
104
  const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
104
105
  startSpinner(reportSpinner);
105
- const [reports, reportId] = await scaUpload.scaTreeUpload(messageToSend, config);
106
- auditReport.processAuditReport(config, reports[0]);
106
+ const { reportArray, reportId } = await scaUpload.scaTreeUpload(messageToSend, config);
107
+ const reportModelLibraryList = convertGenericToTypedReportModelSca(reportArray);
108
+ auditReport.processAuditReport(config, reportModelLibraryList);
107
109
  succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
108
110
  if (config.save !== undefined) {
109
111
  await auditSave.auditSave(config, reportId);
@@ -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.20';
16
16
  const TIMEOUT = 120000;
17
17
  const HIGH_COLOUR = '#ff9900';
18
18
  const CRITICAL_COLOUR = '#e35858';
@@ -134,7 +134,10 @@ const en_locales = () => {
134
134
  chalk.bold('\ncontrast scan') +
135
135
  " to run Contrast's industry leading SAST scanner. \nSupports Java, JavaScript and .Net \n" +
136
136
  chalk.bold('\ncontrast audit') +
137
- ' to find vulnerabilities in your open source dependencies.\nSupports Java, .NET, Node, Ruby, Python, Go and PHP \n' +
137
+ ' to find vulnerabilities in your open source dependencies.' +
138
+ '\nSupports Java, .NET, Node, Ruby, Python, Go and PHP.' +
139
+ '\nOur CLI runs native build tools to generate a complete dependency tree.' +
140
+ '\nIf you are running on untrusted code, consider running in a sandbox.\n' +
138
141
  chalk.bold('\ncontrast lambda') +
139
142
  ' to secure your AWS serverless functions. \nSupports Java and Python \n' +
140
143
  chalk.bold('\ncontrast help') +
@@ -181,7 +184,8 @@ const en_locales = () => {
181
184
  constantsAuditPrerequisitesContentSupportedLanguages: 'Supported languages and their requirements are:',
182
185
  constantsAuditPrerequisitesJavaContentMessage: `
183
186
  ${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`,
187
+ ${chalk.bold('Or')} build.gradle ${chalk.bold('and')} gradle dependencies or ./gradlew dependencies must be supported
188
+ If you are running on untrusted code, consider running in a sandbox.`,
185
189
  constantsAuditPrerequisitesContentDotNetMessage: `
186
190
  ${chalk.bold('.NET framework and .NET core:')} MSBuild 15.0 or greater and a packages.lock.json file.
187
191
  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`,
@@ -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
+ };
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ScaReportRemediationAdviceModel = exports.ScaReportVulnerabilityModel = exports.ScaReportModel = void 0;
4
+ class ScaReportModel {
5
+ constructor(library) {
6
+ this.uuid = library.uuid;
7
+ this.groupName = library.groupName;
8
+ this.artifactName = library.artifactName;
9
+ this.version = library.version;
10
+ this.hash = library.hash;
11
+ this.fileName = library.fileName;
12
+ this.libraryLanguage = library.libraryLanguage;
13
+ this.vulnerable = library.vulnerable;
14
+ this.privateLibrary = library.privateLibrary;
15
+ this.severity = library.severity;
16
+ this.releaseDate = library.releaseDate;
17
+ this.latestVersionReleaseDate = library.latestVersionReleaseDate;
18
+ this.latestVersion = library.latestVersion;
19
+ this.versionsBehind = library.versionsBehind;
20
+ this.vulnerabilities = library.vulnerabilities;
21
+ this.remediationAdvice = library.remediationAdvice;
22
+ }
23
+ }
24
+ exports.ScaReportModel = ScaReportModel;
25
+ class ScaReportVulnerabilityModel {
26
+ constructor(name, description, cvss2Vector, severityValue, severity, cvss3Vector, cvss3SeverityValue, cvss3Severity, hasCvss3) {
27
+ this.name = name;
28
+ this.description = description;
29
+ this.cvss2Vector = cvss2Vector;
30
+ this.severityValue = severityValue;
31
+ this.severity = severity;
32
+ this.cvss3Vector = cvss3Vector;
33
+ this.cvss3SeverityValue = cvss3SeverityValue;
34
+ this.cvss3Severity = cvss3Severity;
35
+ this.hasCvss3 = hasCvss3;
36
+ }
37
+ }
38
+ exports.ScaReportVulnerabilityModel = ScaReportVulnerabilityModel;
39
+ class ScaReportRemediationAdviceModel {
40
+ constructor(closestStableVersion, latestStableVersion) {
41
+ this.closestStableVersion = closestStableVersion;
42
+ this.latestStableVersion = latestStableVersion;
43
+ }
44
+ }
45
+ exports.ScaReportRemediationAdviceModel = ScaReportRemediationAdviceModel;
@@ -44,16 +44,17 @@ const scaTreeUpload = async (analysis, config) => {
44
44
  if (res.body.status === 'COMPLETED') {
45
45
  keepChecking = false;
46
46
  return client.scaServiceReport(config, reportID).then(res => {
47
- return [res.body, reportID];
47
+ const reportBody = res.body;
48
+ return { reportBody, reportID };
48
49
  });
49
50
  }
50
51
  });
51
52
  if (!keepChecking) {
52
- return [res, reportID];
53
+ return { reportArray: res.reportBody, reportID };
53
54
  }
54
55
  await requestUtils.sleep(5000);
55
56
  }
56
- return [res, reportID];
57
+ return { reportArray: res, reportID };
57
58
  };
58
59
  module.exports = {
59
60
  scaTreeUpload
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.severityCountSingleCVESca = exports.severityCountAllCVEsSca = exports.severityCountAllLibrariesSca = exports.convertGenericToTypedReportModelSca = exports.findCVESeveritySca = exports.orderByHighestPrioritySca = exports.findHighestSeverityCVESca = void 0;
4
+ const lodash_1 = require("lodash");
5
+ const constants_1 = require("../../../constants/constants");
6
+ const reportSeverityModel_1 = require("../../../audit/report/models/reportSeverityModel");
7
+ const ScaReportModel_1 = require("../models/ScaReportModel");
8
+ function findHighestSeverityCVESca(cveArray) {
9
+ const mappedToReportSeverityModels = cveArray.map(cve => findCVESeveritySca(cve));
10
+ return (0, lodash_1.orderBy)(mappedToReportSeverityModels, cve => cve?.priority)[0];
11
+ }
12
+ exports.findHighestSeverityCVESca = findHighestSeverityCVESca;
13
+ function orderByHighestPrioritySca(reportSeverityModel) {
14
+ return (0, lodash_1.orderBy)(reportSeverityModel, ['priority'], ['asc']);
15
+ }
16
+ exports.orderByHighestPrioritySca = orderByHighestPrioritySca;
17
+ function findCVESeveritySca(vulnerabilityModel) {
18
+ const { name } = vulnerabilityModel;
19
+ if (vulnerabilityModel.cvss3Severity === 'CRITICAL' ||
20
+ vulnerabilityModel.severity === 'CRITICAL') {
21
+ return new reportSeverityModel_1.ReportSeverityModel('CRITICAL', constants_1.CRITICAL_PRIORITY, constants_1.CRITICAL_COLOUR, name);
22
+ }
23
+ else if (vulnerabilityModel.cvss3Severity === 'HIGH' ||
24
+ vulnerabilityModel.severity === 'HIGH') {
25
+ return new reportSeverityModel_1.ReportSeverityModel('HIGH', constants_1.HIGH_PRIORITY, constants_1.HIGH_COLOUR, name);
26
+ }
27
+ else if (vulnerabilityModel.cvss3Severity === 'MEDIUM' ||
28
+ vulnerabilityModel.severity === 'MEDIUM') {
29
+ return new reportSeverityModel_1.ReportSeverityModel('MEDIUM', constants_1.MEDIUM_PRIORITY, constants_1.MEDIUM_COLOUR, name);
30
+ }
31
+ else if (vulnerabilityModel.cvss3Severity === 'LOW' ||
32
+ vulnerabilityModel.severity === 'LOW') {
33
+ return new reportSeverityModel_1.ReportSeverityModel('LOW', constants_1.LOW_PRIORITY, constants_1.LOW_COLOUR, name);
34
+ }
35
+ else if (vulnerabilityModel.cvss3Severity === 'NOTE' ||
36
+ vulnerabilityModel.severity === 'NOTE') {
37
+ return new reportSeverityModel_1.ReportSeverityModel('NOTE', constants_1.NOTE_PRIORITY, constants_1.NOTE_COLOUR, name);
38
+ }
39
+ }
40
+ exports.findCVESeveritySca = findCVESeveritySca;
41
+ function convertGenericToTypedReportModelSca(reportArray) {
42
+ return reportArray.map((library) => {
43
+ return new ScaReportModel_1.ScaReportModel(library);
44
+ });
45
+ }
46
+ exports.convertGenericToTypedReportModelSca = convertGenericToTypedReportModelSca;
47
+ function severityCountAllLibrariesSca(vulnerableLibraries, severityCount) {
48
+ vulnerableLibraries.forEach(lib => severityCountAllCVEsSca(lib.vulnerabilities, severityCount));
49
+ return severityCount;
50
+ }
51
+ exports.severityCountAllLibrariesSca = severityCountAllLibrariesSca;
52
+ function severityCountAllCVEsSca(cveArray, severityCount) {
53
+ const severityCountInner = severityCount;
54
+ cveArray.forEach(cve => severityCountSingleCVESca(cve, severityCountInner));
55
+ return severityCountInner;
56
+ }
57
+ exports.severityCountAllCVEsSca = severityCountAllCVEsSca;
58
+ function severityCountSingleCVESca(cve, severityCount) {
59
+ if (cve.cvss3Severity === 'CRITICAL' || cve.severity === 'CRITICAL') {
60
+ severityCount.critical += 1;
61
+ }
62
+ else if (cve.cvss3Severity === 'HIGH' || cve.severity === 'HIGH') {
63
+ severityCount.high += 1;
64
+ }
65
+ else if (cve.cvss3Severity === 'MEDIUM' || cve.severity === 'MEDIUM') {
66
+ severityCount.medium += 1;
67
+ }
68
+ else if (cve.cvss3Severity === 'LOW' || cve.severity === 'LOW') {
69
+ severityCount.low += 1;
70
+ }
71
+ else if (cve.cvss3Severity === 'NOTE' || cve.severity === 'NOTE') {
72
+ severityCount.note += 1;
73
+ }
74
+ return severityCount;
75
+ }
76
+ exports.severityCountSingleCVESca = severityCountSingleCVESca;
@@ -111,34 +111,7 @@ const getJavaBuildDeps = (config, files) => {
111
111
  console.log(err.message.toString());
112
112
  }
113
113
  };
114
- const agreementPrompt = async (config) => {
115
- const rl = readLine.createInterface({
116
- input: process.stdin,
117
- output: process.stdout
118
- });
119
- return new Promise((resolve, reject) => {
120
- rl.question('❔ Do you want to continue? Type Y or N', async (input) => {
121
- if (input.toLowerCase() === 'yes' || input.toLowerCase() === 'y') {
122
- config.javaAgreement = paramHandler.setAgreement(true);
123
- rl.close();
124
- resolve(config);
125
- }
126
- else if (input.toLowerCase() === 'no' || input.toLowerCase() === 'n') {
127
- rl.close();
128
- resolve(process.exit(1));
129
- }
130
- else {
131
- rl.close();
132
- console.log('Invalid Input: Exiting');
133
- resolve(process.exit(1));
134
- }
135
- });
136
- }).catch(e => {
137
- throw e;
138
- });
139
- };
140
114
  module.exports = {
141
115
  getJavaBuildDeps,
142
- determineProjectTypeAndCwd,
143
- agreementPrompt
116
+ determineProjectTypeAndCwd
144
117
  };