@contrast/contrast 1.0.3 → 1.0.4

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 (62) hide show
  1. package/.prettierignore +1 -0
  2. package/README.md +20 -14
  3. package/dist/audit/languageAnalysisEngine/{langugageAnalysisFactory.js → languageAnalysisFactory.js} +2 -12
  4. package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +62 -234
  5. package/dist/audit/languageAnalysisEngine/report/models/reportLibraryModel.js +19 -0
  6. package/dist/audit/languageAnalysisEngine/report/models/reportListModel.js +24 -0
  7. package/dist/audit/languageAnalysisEngine/report/models/reportSeverityModel.js +10 -0
  8. package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +24 -129
  9. package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +85 -0
  10. package/dist/audit/languageAnalysisEngine/sendSnapshot.js +3 -1
  11. package/dist/commands/audit/auditController.js +6 -3
  12. package/dist/commands/scan/processScan.js +4 -3
  13. package/dist/common/HTTPClient.js +19 -26
  14. package/dist/common/versionChecker.js +14 -12
  15. package/dist/constants/constants.js +1 -1
  16. package/dist/constants/lambda.js +3 -1
  17. package/dist/constants/locales.js +17 -10
  18. package/dist/constants.js +5 -1
  19. package/dist/index.js +2 -2
  20. package/dist/lambda/help.js +22 -14
  21. package/dist/lambda/lambda.js +6 -0
  22. package/dist/scan/models/groupedResultsModel.js +10 -0
  23. package/dist/scan/models/resultContentModel.js +2 -0
  24. package/dist/scan/models/scanResultsModel.js +11 -0
  25. package/dist/scan/scan.js +90 -95
  26. package/dist/scan/scanConfig.js +1 -1
  27. package/dist/utils/getConfig.js +3 -0
  28. package/package.json +2 -2
  29. package/src/audit/languageAnalysisEngine/{langugageAnalysisFactory.js → languageAnalysisFactory.js} +2 -16
  30. package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +127 -0
  31. package/src/audit/languageAnalysisEngine/report/models/reportLibraryModel.ts +30 -0
  32. package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +32 -0
  33. package/src/audit/languageAnalysisEngine/report/models/reportSeverityModel.ts +9 -0
  34. package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +56 -0
  35. package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +110 -0
  36. package/src/audit/languageAnalysisEngine/sendSnapshot.js +3 -1
  37. package/src/commands/audit/auditController.ts +12 -3
  38. package/src/commands/scan/processScan.js +4 -6
  39. package/src/common/HTTPClient.js +31 -38
  40. package/src/common/errorHandling.ts +0 -1
  41. package/src/common/versionChecker.ts +24 -22
  42. package/src/constants/constants.js +1 -1
  43. package/src/constants/lambda.js +3 -1
  44. package/src/constants/locales.js +20 -10
  45. package/src/constants.js +7 -1
  46. package/src/index.ts +2 -3
  47. package/src/lambda/help.ts +22 -14
  48. package/src/lambda/lambda.ts +8 -0
  49. package/src/scan/models/groupedResultsModel.ts +18 -0
  50. package/src/scan/models/resultContentModel.ts +86 -0
  51. package/src/scan/models/scanResultsModel.ts +52 -0
  52. package/src/scan/scan.ts +192 -0
  53. package/src/scan/scanConfig.js +1 -1
  54. package/src/scan/scanController.js +2 -0
  55. package/src/utils/getConfig.ts +10 -0
  56. package/dist/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +0 -17
  57. package/dist/audit/languageAnalysisEngine/report/newReportingFeature.js +0 -81
  58. package/src/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +0 -27
  59. package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.js +0 -303
  60. package/src/audit/languageAnalysisEngine/report/newReportingFeature.js +0 -124
  61. package/src/audit/languageAnalysisEngine/report/reportingFeature.js +0 -190
  62. package/src/scan/scan.js +0 -195
package/dist/scan/scan.js CHANGED
@@ -1,44 +1,43 @@
1
1
  "use strict";
2
- const commonApi = require('../utils/commonApi.js');
3
- const fileUtils = require('../scan/fileUtils');
4
- const allowedFileTypes = ['.jar', '.war', '.js', '.zip', '.exe'];
5
- const i18n = require('i18n');
6
- const oraWrapper = require('../utils/oraWrapper');
7
- const chalk = require('chalk');
8
- const isFileAllowed = scanOption => {
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.stripMustacheTags = exports.getMessage = exports.getGroups = exports.formatLinks = exports.formatScanOutput = exports.sendScan = exports.isFileAllowed = exports.allowedFileTypes = void 0;
7
+ const commonApi_js_1 = __importDefault(require("../utils/commonApi.js"));
8
+ const fileUtils_1 = __importDefault(require("../scan/fileUtils"));
9
+ const i18n_1 = __importDefault(require("i18n"));
10
+ const oraWrapper_1 = __importDefault(require("../utils/oraWrapper"));
11
+ const chalk_1 = __importDefault(require("chalk"));
12
+ const groupedResultsModel_1 = require("./models/groupedResultsModel");
13
+ exports.allowedFileTypes = ['.jar', '.war', '.js', '.zip', '.exe'];
14
+ const isFileAllowed = (scanOption) => {
9
15
  let valid = false;
10
- allowedFileTypes.forEach(fileType => {
16
+ exports.allowedFileTypes.forEach(fileType => {
11
17
  if (scanOption.endsWith(fileType)) {
12
18
  valid = true;
13
19
  }
14
20
  });
15
21
  return valid;
16
22
  };
17
- const stripMustacheTags = oldString => {
18
- return oldString
19
- .replace(/\n/g, ' ')
20
- .replace(/{{.*?}}/g, '\n')
21
- .replace(/\$\$LINK_DELIM\$\$/g, '\n')
22
- .replace(/\s+/g, ' ')
23
- .trim();
24
- };
23
+ exports.isFileAllowed = isFileAllowed;
25
24
  const sendScan = async (config) => {
26
- if (!isFileAllowed(config.file)) {
27
- console.log(i18n.__('scanErrorFileMessage'));
25
+ if (!(0, exports.isFileAllowed)(config.file)) {
26
+ console.log(i18n_1.default.__('scanErrorFileMessage'));
28
27
  process.exit(9);
29
28
  }
30
29
  else {
31
- fileUtils.checkFilePermissions(config.file);
32
- const client = commonApi.getHttpClient(config);
33
- const startUploadSpinner = oraWrapper.returnOra(i18n.__('uploadingScan'));
34
- oraWrapper.startSpinner(startUploadSpinner);
30
+ fileUtils_1.default.checkFilePermissions(config.file);
31
+ const client = commonApi_js_1.default.getHttpClient(config);
32
+ const startUploadSpinner = oraWrapper_1.default.returnOra(i18n_1.default.__('uploadingScan'));
33
+ oraWrapper_1.default.startSpinner(startUploadSpinner);
35
34
  return await client
36
35
  .sendArtifact(config)
37
36
  .then(res => {
38
37
  if (res.statusCode === 201) {
39
- oraWrapper.succeedSpinner(startUploadSpinner, i18n.__('uploadingScanSuccessful'));
38
+ oraWrapper_1.default.succeedSpinner(startUploadSpinner, i18n_1.default.__('uploadingScanSuccessful'));
40
39
  if (config.verbose) {
41
- console.log(i18n.__('responseMessage', res.body));
40
+ console.log(i18n_1.default.__('responseMessage', res.body));
42
41
  }
43
42
  return res.body.id;
44
43
  }
@@ -47,12 +46,12 @@ const sendScan = async (config) => {
47
46
  console.log(res.statusCode);
48
47
  console.log(config);
49
48
  }
50
- oraWrapper.failSpinner(startUploadSpinner, i18n.__('uploadingScanFail'));
49
+ oraWrapper_1.default.failSpinner(startUploadSpinner, i18n_1.default.__('uploadingScanFail'));
51
50
  if (res.statusCode === 403) {
52
- console.log(i18n.__('permissionsError'));
51
+ console.log(i18n_1.default.__('permissionsError'));
53
52
  process.exit(1);
54
53
  }
55
- console.log(i18n.__('genericServiceError', res.statusCode));
54
+ console.log(i18n_1.default.__('genericServiceError', res.statusCode));
56
55
  process.exit(1);
57
56
  }
58
57
  })
@@ -61,101 +60,97 @@ const sendScan = async (config) => {
61
60
  });
62
61
  }
63
62
  };
64
- const formatScanOutput = (overview, results) => {
65
- console.log();
66
- if (results.content.length === 0) {
67
- console.log(i18n.__('scanNoVulnerabilitiesFound'));
63
+ exports.sendScan = sendScan;
64
+ function formatScanOutput(scanResults) {
65
+ const { projectOverview, scanResultsInstances } = scanResults;
66
+ if (scanResultsInstances.content.length === 0) {
67
+ console.log(i18n_1.default.__('scanNoVulnerabilitiesFound'));
68
68
  }
69
69
  else {
70
- let message = overview.critical || overview.high
70
+ const message = projectOverview.critical || projectOverview.high
71
71
  ? 'Here are your top priorities to fix'
72
72
  : "No major issues, here's what we found";
73
- console.log(chalk.bold(message));
73
+ console.log(chalk_1.default.bold(message));
74
74
  console.log();
75
- const groups = getGroups(results.content);
75
+ const groups = getGroups(scanResultsInstances.content);
76
76
  groups.forEach(entry => {
77
- console.log(chalk.bold(`${entry.severity} | ${entry.ruleId} (${entry.lineInfoSet.size})`));
77
+ console.log(chalk_1.default.bold(`[ ${entry.severity} ] | ${entry.ruleId} (${entry.lineInfoSet.size}) - ` +
78
+ `${entry.message}`));
78
79
  let count = 1;
79
80
  entry.lineInfoSet.forEach(lineInfo => {
80
81
  console.log(`\t ${count}. ${lineInfo}`);
81
82
  count++;
82
83
  });
83
- if (entry?.cwe && entry?.cwe.length > 0) {
84
- formatLinks('cwe', entry.cwe);
84
+ if (entry?.issue) {
85
+ console.log(chalk_1.default.bold('Issue' + ': ') + entry.issue);
85
86
  }
86
- if (entry?.reference && entry?.reference.length > 0) {
87
- formatLinks('reference', entry.reference);
87
+ if (entry?.advice) {
88
+ console.log(chalk_1.default.bold('Advice' + ': ') + entry.advice);
88
89
  }
89
- if (entry?.owasp && entry?.owasp.length > 0) {
90
- formatLinks('owasp', entry.owasp);
90
+ if (entry?.learn && entry?.learn.length > 0) {
91
+ formatLinks('Learn', entry.learn);
91
92
  }
92
- console.log(chalk.bold('How to fix:'));
93
- console.log(entry.recommendation);
94
93
  console.log();
95
94
  });
96
- const totalVulnerabilities = overview.critical +
97
- overview.high +
98
- overview.medium +
99
- overview.low +
100
- overview.note;
101
- let vulMessage = totalVulnerabilities === 1 ? `vulnerability` : `vulnerabilities`;
102
- console.log(chalk.bold(`Found ${totalVulnerabilities} ${vulMessage}`));
103
- console.log(i18n.__('foundDetailedVulnerabilities', overview.critical, overview.high, overview.medium, overview.low, overview.note));
95
+ printVulnInfo(projectOverview);
104
96
  }
105
- };
106
- const formatLinks = (objName, entry) => {
107
- console.log(chalk.bold(objName + ':'));
97
+ }
98
+ exports.formatScanOutput = formatScanOutput;
99
+ function printVulnInfo(projectOverview) {
100
+ const totalVulnerabilities = getTotalVulns(projectOverview);
101
+ const vulMessage = totalVulnerabilities === 1 ? `vulnerability` : `vulnerabilities`;
102
+ console.log(chalk_1.default.bold(`Found ${totalVulnerabilities} ${vulMessage}`));
103
+ console.log(i18n_1.default.__('foundDetailedVulnerabilities', String(projectOverview.critical), String(projectOverview.high), String(projectOverview.medium), String(projectOverview.low), String(projectOverview.note)));
104
+ }
105
+ function getTotalVulns(projectOverview) {
106
+ return (projectOverview.critical +
107
+ projectOverview.high +
108
+ projectOverview.medium +
109
+ projectOverview.low +
110
+ projectOverview.note);
111
+ }
112
+ function formatLinks(objName, entry) {
113
+ console.log(chalk_1.default.bold(objName + ':'));
108
114
  entry.forEach(link => {
109
115
  console.log(link);
110
116
  });
111
- console.log();
112
- };
113
- const getGroups = content => {
117
+ }
118
+ exports.formatLinks = formatLinks;
119
+ function getGroups(content) {
114
120
  const groupTypeSet = new Set(content.map(({ ruleId }) => ruleId));
115
- let groupTypeResults = [];
121
+ const groupTypeResults = [];
116
122
  groupTypeSet.forEach(groupName => {
117
- let groupResultsObj = {
118
- ruleId: groupName,
119
- lineInfoSet: new Set(),
120
- cwe: '',
121
- owasp: '',
122
- reference: '',
123
- recommendation: '',
124
- severity: ''
125
- };
123
+ const groupResultsObj = new groupedResultsModel_1.GroupedResultsModel(groupName);
126
124
  content.forEach(resultEntry => {
127
125
  if (resultEntry.ruleId === groupName) {
128
126
  groupResultsObj.severity = resultEntry.severity;
129
- groupResultsObj.cwe = resultEntry.cwe;
130
- groupResultsObj.owasp = resultEntry.owasp;
131
- groupResultsObj.reference = resultEntry.reference;
132
- groupResultsObj.recommendation = resultEntry.recommendation
133
- ? stripMustacheTags(resultEntry.recommendation)
134
- : 'No Recommendations Data Found';
135
- groupResultsObj.lineInfoSet.add(formattedCodeLine(resultEntry));
127
+ groupResultsObj.issue = stripMustacheTags(resultEntry.issue);
128
+ groupResultsObj.advice = resultEntry.advice;
129
+ groupResultsObj.learn = resultEntry.learn;
130
+ groupResultsObj.message = resultEntry.message?.text;
131
+ groupResultsObj.lineInfoSet.add(getMessage(resultEntry.locations));
136
132
  }
137
133
  });
138
134
  groupTypeResults.push(groupResultsObj);
139
135
  });
140
136
  return groupTypeResults;
141
- };
142
- const formattedCodeLine = resultEntry => {
143
- let lineUri = resultEntry.locations[0]?.physicalLocation.artifactLocation.uri;
144
- return lineUri + ' @ ' + setLineNumber(resultEntry);
145
- };
146
- const setLineNumber = resultEntry => {
147
- return resultEntry.codeFlows?.[0]?.threadFlows[0]?.locations[0]?.location
148
- ?.physicalLocation?.region?.startLine
149
- ? resultEntry.codeFlows[0]?.threadFlows[0]?.locations[0]?.location
150
- ?.physicalLocation?.region?.startLine
151
- : resultEntry.locations[0]?.physicalLocation?.region?.startLine;
152
- };
153
- module.exports = {
154
- sendScan: sendScan,
155
- getGroups: getGroups,
156
- allowedFileTypes: allowedFileTypes,
157
- isFileAllowed: isFileAllowed,
158
- stripMustacheTags: stripMustacheTags,
159
- formatScanOutput: formatScanOutput,
160
- formatLinks: formatLinks
161
- };
137
+ }
138
+ exports.getGroups = getGroups;
139
+ function getMessage(locations) {
140
+ const message = locations[0]?.physicalLocation?.artifactLocation?.uri || '';
141
+ const lineNumber = locations[0]?.physicalLocation?.region?.startLine || '';
142
+ if (!lineNumber) {
143
+ return '@' + message;
144
+ }
145
+ return '@' + message + ':' + lineNumber;
146
+ }
147
+ exports.getMessage = getMessage;
148
+ function stripMustacheTags(oldString) {
149
+ return oldString
150
+ .replace(/\n/g, ' ')
151
+ .replace(/{{.*?}}/g, '\n')
152
+ .replace(/\$\$LINK_DELIM\$\$/g, '\n')
153
+ .replace(/\s+/g, ' ')
154
+ .trim();
155
+ }
156
+ exports.stripMustacheTags = stripMustacheTags;
@@ -18,7 +18,7 @@ const getScanConfig = argv => {
18
18
  if (!Object.values(supportedLanguages).includes(scanParams.language)) {
19
19
  console.log(`Did not recognise --language ${scanParams.language}`);
20
20
  console.log(i18n.__('constantsHowToRunDev3'));
21
- process.exit(0);
21
+ process.exit(1);
22
22
  }
23
23
  }
24
24
  if (!scanParams.name && scanParams.file) {
@@ -10,6 +10,9 @@ const localConfig = (name, version) => {
10
10
  configName: name
11
11
  });
12
12
  config.set('version', version);
13
+ if (process.env.CONTRAST_CODSEC_DISABLE_UPDATE_MESSAGE) {
14
+ config.set('updateMessageHidden', JSON.parse(process.env.CONTRAST_CODSEC_DISABLE_UPDATE_MESSAGE.toLowerCase()));
15
+ }
13
16
  if (!config.has('host')) {
14
17
  config.set('host', 'https://ce.contrastsecurity.com/');
15
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/contrast",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Contrast Security's command line tool",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -35,7 +35,7 @@
35
35
  "dev": "npx ts-node src/index.ts"
36
36
  },
37
37
  "engines": {
38
- "node": ">=16.13.2 <17"
38
+ "node": ">=16"
39
39
  },
40
40
  "dependencies": {
41
41
  "@aws-sdk/client-iam": "^3.78.0",
@@ -10,8 +10,6 @@ const pythonAE = require('../pythonAnalysisEngine')
10
10
  const phpAE = require('../phpAnalysisEngine')
11
11
  const goAE = require('../goAnalysisEngine')
12
12
  const { vulnerabilityReport } = require('./report/reportingFeature')
13
- const { vulnReportWithoutDevDep } = require('./report/newReportingFeature')
14
- const { checkDevDeps } = require('./report/checkIgnoreDevDep')
15
13
  const { newSendSnapShot } = require('../languageAnalysisEngine/sendSnapshot')
16
14
  const fs = require('fs')
17
15
  const chalk = require('chalk')
@@ -50,19 +48,7 @@ module.exports = exports = (err, analysis) => {
50
48
  console.log('\n **************CONTRAST OSS ANALYSIS BEGINS**************')
51
49
  const snapshotResponse = await newSendSnapShot(analysis, catalogueAppId)
52
50
 
53
- if (config.report) {
54
- const ignoreDevUrl = await checkDevDeps(config)
55
- if (ignoreDevUrl) {
56
- await vulnReportWithoutDevDep(
57
- analysis,
58
- catalogueAppId,
59
- snapshotResponse.id,
60
- config
61
- )
62
- } else {
63
- await vulnerabilityReport(analysis, catalogueAppId, config)
64
- }
65
- }
51
+ await vulnerabilityReport(analysis, catalogueAppId, snapshotResponse.id)
66
52
 
67
53
  //should be moved to processAudit.ts once promises implemented
68
54
  await auditSave(config)
@@ -120,7 +106,7 @@ async function auditSave(config) {
120
106
  } else {
121
107
  console.log(i18n.__('auditBadFiletypeSpecifiedForSave'))
122
108
  }
123
- } else {
109
+ } else if (config.save === null) {
124
110
  console.log(i18n.__('auditNoFiletypeSpecifiedForSave'))
125
111
  }
126
112
  }
@@ -0,0 +1,127 @@
1
+ import i18n from 'i18n'
2
+ import { getHttpClient, handleResponseErrors } from '../../../utils/commonApi'
3
+ import {
4
+ ReportCompositeKey,
5
+ ReportList,
6
+ ReportModelStructure
7
+ } from './models/reportListModel'
8
+ import { ReportSeverityModel } from './models/reportSeverityModel'
9
+ import { orderBy } from 'lodash'
10
+ import chalk from 'chalk'
11
+ import { ReportLibraryModel } from './models/reportLibraryModel'
12
+ import { findHighestSeverityCVE, findNameAndVersion } from './utils/reportUtils'
13
+ import {
14
+ failSpinner,
15
+ returnOra,
16
+ startSpinner,
17
+ succeedSpinner
18
+ } from '../../../utils/oraWrapper'
19
+
20
+ export const createLibraryHeader = (
21
+ id: string,
22
+ numberOfVulnerableLibraries: number,
23
+ numberOfCves: number,
24
+ name: string
25
+ ) => {
26
+ name
27
+ ? console.log(`\n Application Name: ${name} | Application ID: ${id}`)
28
+ : console.log(` Application ID: ${id}`)
29
+
30
+ numberOfVulnerableLibraries === 1
31
+ ? console.log(
32
+ '\n **************************' +
33
+ ` Found 1 vulnerable library containing ${numberOfCves} CVE's` +
34
+ '************************** '
35
+ )
36
+ : console.log(
37
+ '\n **************************' +
38
+ ` Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVE's ` +
39
+ '************************** '
40
+ )
41
+ }
42
+
43
+ export const getReport = async (config: any, reportId: string) => {
44
+ const client = getHttpClient(config)
45
+
46
+ const reportSpinner = returnOra(i18n.__('auditReportWaiting'))
47
+ reportSpinner.indent = 1
48
+ startSpinner(reportSpinner)
49
+ return client
50
+ .getReportById(config, reportId)
51
+ .then((res: { statusCode: number; body: any }) => {
52
+ if (res.statusCode === 200) {
53
+ succeedSpinner(reportSpinner, i18n.__('auditReportSuccessMessage'))
54
+ return res.body
55
+ } else {
56
+ failSpinner(reportSpinner, i18n.__('auditReportFail'))
57
+ console.log('config-------------------')
58
+ console.log(config)
59
+ console.log('reportId----------------')
60
+ console.log(reportId)
61
+ console.log(JSON.stringify(res))
62
+ handleResponseErrors(res, 'report')
63
+ }
64
+ })
65
+ .catch((err: any) => {
66
+ console.log(err)
67
+ })
68
+ }
69
+
70
+ export const printVulnerabilityResponse = (
71
+ vulnerabilities: ReportLibraryModel[],
72
+ config: any
73
+ ) => {
74
+ let hasSomeVulnerabilitiesReported = false
75
+ printFormattedOutput(vulnerabilities, config)
76
+ if (Object.keys(vulnerabilities).length > 0) {
77
+ hasSomeVulnerabilitiesReported = true
78
+ }
79
+ return hasSomeVulnerabilitiesReported
80
+ }
81
+
82
+ export const printFormattedOutput = (
83
+ libraries: ReportLibraryModel[],
84
+ config: any
85
+ ) => {
86
+ const report = new ReportList()
87
+
88
+ for (const library of libraries) {
89
+ const { name, version } = findNameAndVersion(library, config)
90
+
91
+ const newOutputModel = new ReportModelStructure(
92
+ new ReportCompositeKey(
93
+ name,
94
+ version,
95
+ findHighestSeverityCVE(library.cveArray) as ReportSeverityModel
96
+ ),
97
+ library.cveArray
98
+ )
99
+
100
+ report.reportOutputList.push(newOutputModel)
101
+ }
102
+
103
+ const orderedOutputList = orderBy(
104
+ report.reportOutputList,
105
+ reportListItem => reportListItem.compositeKey.highestSeverity.priority
106
+ )
107
+
108
+ for (const reportModel of orderedOutputList) {
109
+ const name = reportModel.compositeKey.libraryName
110
+ const version = reportModel.compositeKey.libraryVersion
111
+ const highestSeverity = reportModel.compositeKey.highestSeverity.severity
112
+
113
+ const numOfCVEs = reportModel.cveArray.length
114
+
115
+ const cveNames: string[] = []
116
+
117
+ reportModel.cveArray.forEach(cve => cveNames.push(cve.name as string))
118
+
119
+ const boldHeader = chalk.bold(`${highestSeverity} | Vulnerable Library`)
120
+ const cvePluralised = numOfCVEs > 1 ? 'CVEs' : 'CVE'
121
+ console.log(
122
+ `\n ${boldHeader} ${name} (${version}) has ${numOfCVEs} known ${cvePluralised}`
123
+ )
124
+ console.log(` ${cveNames.join(', ')}`)
125
+ console.log(chalk.bold(' How to fix: Update to latest version'))
126
+ }
127
+ }
@@ -0,0 +1,30 @@
1
+ export class ReportLibraryModel {
2
+ name: string
3
+ cveArray: ReportCVEModel[]
4
+
5
+ constructor (name: string, cveArray: ReportCVEModel[]){
6
+ this.name = name
7
+ this.cveArray = cveArray
8
+ }
9
+ }
10
+
11
+ export class ReportCVEModel {
12
+ name?: string
13
+ description?: string
14
+ authentication?: string
15
+ references?: []
16
+ severityCode?: string
17
+ cvss3SeverityCode?: string
18
+
19
+ constructor (
20
+ name: string,
21
+ description: string,
22
+ severityCode: string,
23
+ cvss3SeverityCode: string
24
+ ){
25
+ this.name = name
26
+ this.description = description
27
+ this.severityCode = severityCode
28
+ this.cvss3SeverityCode = cvss3SeverityCode
29
+ }
30
+ }
@@ -0,0 +1,32 @@
1
+ import {ReportSeverityModel} from "./reportSeverityModel";
2
+ import {ReportCVEModel} from "./reportLibraryModel";
3
+
4
+ export class ReportList {
5
+ reportOutputList: ReportModelStructure[]
6
+
7
+ constructor (){
8
+ this.reportOutputList = []
9
+ }
10
+ }
11
+
12
+ export class ReportModelStructure {
13
+ compositeKey: ReportCompositeKey;
14
+ cveArray: ReportCVEModel[];
15
+
16
+ constructor (compositeKey: ReportCompositeKey, cveArray: ReportCVEModel[]){
17
+ this.compositeKey = compositeKey
18
+ this.cveArray = cveArray
19
+ }
20
+ }
21
+
22
+ export class ReportCompositeKey {
23
+ libraryName!: string;
24
+ libraryVersion!: string;
25
+ highestSeverity!: ReportSeverityModel;
26
+
27
+ constructor (libraryName: string, libraryVersion: string, highestSeverity: ReportSeverityModel){
28
+ this.libraryName = libraryName
29
+ this.libraryVersion = libraryVersion
30
+ this.highestSeverity = highestSeverity
31
+ }
32
+ }
@@ -0,0 +1,9 @@
1
+ export class ReportSeverityModel {
2
+ severity!: string
3
+ priority!: number
4
+
5
+ constructor(severity: string, priority: number) {
6
+ this.severity = severity
7
+ this.priority = priority
8
+ }
9
+ }
@@ -0,0 +1,56 @@
1
+ import {
2
+ createLibraryHeader,
3
+ getReport,
4
+ printVulnerabilityResponse
5
+ } from './commonReportingFunctions'
6
+ import {
7
+ convertGenericToTypedLibraries,
8
+ severityCount
9
+ } from './utils/reportUtils'
10
+
11
+ export async function vulnerabilityReport(
12
+ analysis: any,
13
+ applicationId: string,
14
+ reportId: string
15
+ ) {
16
+ const reportResponse = await getReport(analysis.config, reportId)
17
+
18
+ if (reportResponse !== undefined) {
19
+ const id = applicationId
20
+ const name = analysis.config.applicationName
21
+ formatVulnerabilityOutput(
22
+ reportResponse.vulnerabilities,
23
+ id,
24
+ name,
25
+ analysis.config
26
+ )
27
+ }
28
+ }
29
+
30
+ export function formatVulnerabilityOutput(
31
+ libraryVulnerabilityResponse: any,
32
+ id: string,
33
+ name: string,
34
+ config: any
35
+ ) {
36
+ const vulnerableLibraries = convertGenericToTypedLibraries(
37
+ libraryVulnerabilityResponse
38
+ )
39
+
40
+ const numberOfVulnerableLibraries = vulnerableLibraries.length
41
+ let numberOfCves = 0
42
+ vulnerableLibraries.forEach(lib => (numberOfCves += lib.cveArray.length))
43
+
44
+ createLibraryHeader(id, numberOfVulnerableLibraries, numberOfCves, name)
45
+
46
+ const hasSomeVulnerabilitiesReported = printVulnerabilityResponse(
47
+ vulnerableLibraries,
48
+ config
49
+ )
50
+
51
+ return [
52
+ hasSomeVulnerabilitiesReported,
53
+ numberOfCves,
54
+ severityCount(vulnerableLibraries)
55
+ ]
56
+ }