@contrast/contrast 1.0.7 → 1.0.8
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.
- package/dist/audit/autodetection/autoDetectLanguage.js +3 -3
- package/dist/audit/catalogueApplication/catalogueApplication.js +23 -5
- package/dist/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +5 -5
- package/dist/audit/languageAnalysisEngine/getProjectRootFilenames.js +9 -9
- package/dist/audit/languageAnalysisEngine/index.js +2 -2
- package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +5 -28
- package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +11 -4
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +39 -13
- package/dist/audit/languageAnalysisEngine/report/models/reportListModel.js +2 -1
- package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +3 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +35 -14
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +3 -3
- package/dist/audit/save.js +29 -0
- package/dist/commands/audit/auditController.js +21 -5
- package/dist/commands/audit/help.js +24 -1
- package/dist/commands/audit/processAudit.js +7 -1
- package/dist/commands/audit/saveFile.js +7 -3
- package/dist/commands/scan/sca/scaAnalysis.js +31 -10
- package/dist/common/HTTPClient.js +6 -0
- package/dist/common/versionChecker.js +19 -4
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +12 -11
- package/dist/constants.js +9 -4
- package/dist/index.js +4 -3
- package/dist/sbom/generateSbom.js +4 -3
- package/dist/scaAnalysis/common/formatMessage.js +26 -5
- package/dist/scaAnalysis/common/treeUpload.js +0 -1
- package/dist/scaAnalysis/go/goReadDepFile.js +1 -3
- package/dist/scaAnalysis/java/analysis.js +5 -5
- package/dist/scaAnalysis/javascript/analysis.js +110 -0
- package/dist/scaAnalysis/javascript/index.js +41 -0
- package/dist/scaAnalysis/php/analysis.js +89 -0
- package/dist/scaAnalysis/php/index.js +10 -0
- package/dist/scaAnalysis/python/analysis.js +8 -7
- package/dist/scaAnalysis/ruby/analysis.js +8 -8
- package/dist/scaAnalysis/ruby/index.js +2 -2
- package/dist/scan/autoDetection.js +4 -4
- package/dist/scan/fileUtils.js +13 -2
- package/dist/utils/filterProjectPath.js +7 -2
- package/package.json +3 -3
- package/src/audit/autodetection/autoDetectLanguage.ts +3 -3
- package/src/audit/catalogueApplication/catalogueApplication.js +28 -6
- package/src/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +5 -5
- package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +11 -11
- package/src/audit/languageAnalysisEngine/index.js +2 -2
- package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +4 -32
- package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +20 -19
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +67 -17
- package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +4 -1
- package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +4 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +49 -17
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +1 -1
- package/src/audit/save.js +32 -0
- package/src/commands/audit/auditController.ts +22 -13
- package/src/commands/audit/help.ts +24 -1
- package/src/commands/audit/processAudit.ts +6 -3
- package/src/commands/audit/saveFile.ts +5 -1
- package/src/commands/scan/sca/scaAnalysis.js +53 -22
- package/src/common/HTTPClient.js +7 -0
- package/src/common/versionChecker.ts +23 -4
- package/src/constants/constants.js +1 -1
- package/src/constants/locales.js +12 -11
- package/src/constants.js +9 -4
- package/src/index.ts +5 -3
- package/src/sbom/generateSbom.ts +1 -1
- package/src/scaAnalysis/common/formatMessage.js +27 -5
- package/src/scaAnalysis/common/treeUpload.js +0 -1
- package/src/scaAnalysis/go/goReadDepFile.js +1 -3
- package/src/scaAnalysis/java/analysis.js +5 -5
- package/src/scaAnalysis/javascript/analysis.js +127 -0
- package/src/scaAnalysis/javascript/index.js +56 -0
- package/src/scaAnalysis/php/analysis.js +98 -0
- package/src/scaAnalysis/php/index.js +11 -0
- package/src/scaAnalysis/python/analysis.js +8 -7
- package/src/scaAnalysis/ruby/analysis.js +8 -8
- package/src/scaAnalysis/ruby/index.js +2 -2
- package/src/scan/autoDetection.js +4 -4
- package/src/scan/fileUtils.js +13 -2
- package/src/utils/filterProjectPath.js +6 -2
|
@@ -8,14 +8,14 @@ const i18n_1 = __importDefault(require("i18n"));
|
|
|
8
8
|
const reduceIdentifiedLanguages_1 = require("../languageAnalysisEngine/reduceIdentifiedLanguages");
|
|
9
9
|
const getProjectRootFilenames_1 = require("../languageAnalysisEngine/getProjectRootFilenames");
|
|
10
10
|
function identifyLanguages(config) {
|
|
11
|
-
const {
|
|
12
|
-
const projectRootFilenames = (0, getProjectRootFilenames_1.getProjectRootFilenames)(
|
|
11
|
+
const { file } = config;
|
|
12
|
+
const projectRootFilenames = (0, getProjectRootFilenames_1.getProjectRootFilenames)(file);
|
|
13
13
|
const identifiedLanguages = projectRootFilenames.reduce((accumulator, filename) => {
|
|
14
14
|
const deducedLanguages = (0, reduceIdentifiedLanguages_1.deduceLanguage)(filename);
|
|
15
15
|
return [...accumulator, ...deducedLanguages];
|
|
16
16
|
}, []);
|
|
17
17
|
if (Object.keys(identifiedLanguages).length === 0) {
|
|
18
|
-
throw new Error(i18n_1.default.__('languageAnalysisNoLanguage',
|
|
18
|
+
throw new Error(i18n_1.default.__('languageAnalysisNoLanguage', file));
|
|
19
19
|
}
|
|
20
20
|
return (0, reduceIdentifiedLanguages_1.reduceIdentifiedLanguages)(identifiedLanguages);
|
|
21
21
|
}
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const i18n = require('i18n');
|
|
3
2
|
const { getHttpClient, handleResponseErrors } = require('../../utils/commonApi');
|
|
4
|
-
const displaySuccessMessage = () => {
|
|
5
|
-
console.log(i18n.__('catalogueSuccessCommand'));
|
|
6
|
-
};
|
|
7
3
|
const catalogueApplication = async (config) => {
|
|
8
4
|
const client = getHttpClient(config);
|
|
9
5
|
let appId;
|
|
@@ -13,6 +9,9 @@ const catalogueApplication = async (config) => {
|
|
|
13
9
|
if (res.statusCode === 201) {
|
|
14
10
|
appId = res.body.application.app_id;
|
|
15
11
|
}
|
|
12
|
+
else if (doesMessagesContainAppId(res)) {
|
|
13
|
+
appId = tryRetrieveAppIdFromMessages(res.body.messages);
|
|
14
|
+
}
|
|
16
15
|
else {
|
|
17
16
|
handleResponseErrors(res, 'catalogue');
|
|
18
17
|
}
|
|
@@ -22,6 +21,25 @@ const catalogueApplication = async (config) => {
|
|
|
22
21
|
});
|
|
23
22
|
return appId;
|
|
24
23
|
};
|
|
24
|
+
const doesMessagesContainAppId = res => {
|
|
25
|
+
const regex = /(Application ID =)/;
|
|
26
|
+
if (res.statusCode === 400 &&
|
|
27
|
+
res.body.messages.filter(message => regex.exec(message))[0]) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
};
|
|
32
|
+
const tryRetrieveAppIdFromMessages = messages => {
|
|
33
|
+
let appId;
|
|
34
|
+
messages.forEach(message => {
|
|
35
|
+
if (message.includes('Application ID')) {
|
|
36
|
+
appId = message.split('=')[1].replace(/\s+/g, '');
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return appId;
|
|
40
|
+
};
|
|
25
41
|
module.exports = {
|
|
26
|
-
catalogueApplication: catalogueApplication
|
|
42
|
+
catalogueApplication: catalogueApplication,
|
|
43
|
+
doesMessagesContainAppId,
|
|
44
|
+
tryRetrieveAppIdFromMessages
|
|
27
45
|
};
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const path = require('path');
|
|
3
3
|
module.exports = exports = (analysis, next) => {
|
|
4
|
-
const {
|
|
5
|
-
languageAnalysis.identifiedLanguageInfo = getIdentifiedLanguageInfo(
|
|
4
|
+
const { file, languageAnalysis } = analysis;
|
|
5
|
+
languageAnalysis.identifiedLanguageInfo = getIdentifiedLanguageInfo(file, languageAnalysis.identifiedLanguages);
|
|
6
6
|
next();
|
|
7
7
|
};
|
|
8
|
-
const getIdentifiedLanguageInfo = (
|
|
8
|
+
const getIdentifiedLanguageInfo = (file, identifiedLanguages) => {
|
|
9
9
|
const [language] = Object.keys(identifiedLanguages);
|
|
10
10
|
const { projectFilenames: [projectFilename], lockFilenames: [lockFilename] } = Object.values(identifiedLanguages)[0];
|
|
11
11
|
let identifiedLanguageInfo = {
|
|
12
12
|
language,
|
|
13
13
|
projectFilename,
|
|
14
|
-
projectFilePath: path.join(
|
|
14
|
+
projectFilePath: path.join(file, projectFilename)
|
|
15
15
|
};
|
|
16
16
|
if (lockFilename) {
|
|
17
17
|
identifiedLanguageInfo = {
|
|
18
18
|
...identifiedLanguageInfo,
|
|
19
19
|
lockFilename,
|
|
20
|
-
lockFilePath: path.join(
|
|
20
|
+
lockFilePath: path.join(file, lockFilename)
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
return identifiedLanguageInfo;
|
|
@@ -3,9 +3,9 @@ const fs = require('fs');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const i18n = require('i18n');
|
|
5
5
|
module.exports = exports = (analysis, next) => {
|
|
6
|
-
const {
|
|
6
|
+
const { file, languageAnalysis } = analysis;
|
|
7
7
|
try {
|
|
8
|
-
languageAnalysis.projectRootFilenames = getProjectRootFilenames(
|
|
8
|
+
languageAnalysis.projectRootFilenames = getProjectRootFilenames(file);
|
|
9
9
|
}
|
|
10
10
|
catch (err) {
|
|
11
11
|
next(err);
|
|
@@ -13,27 +13,27 @@ module.exports = exports = (analysis, next) => {
|
|
|
13
13
|
}
|
|
14
14
|
next();
|
|
15
15
|
};
|
|
16
|
-
const getProjectRootFilenames =
|
|
16
|
+
const getProjectRootFilenames = file => {
|
|
17
17
|
let projectStats = null;
|
|
18
18
|
try {
|
|
19
|
-
projectStats = fs.statSync(
|
|
19
|
+
projectStats = fs.statSync(file);
|
|
20
20
|
}
|
|
21
21
|
catch (err) {
|
|
22
|
-
throw new Error(i18n.__('languageAnalysisProjectRootFileNameFailure',
|
|
22
|
+
throw new Error(i18n.__('languageAnalysisProjectRootFileNameFailure', file) +
|
|
23
23
|
`${err.message}`);
|
|
24
24
|
}
|
|
25
25
|
if (projectStats.isDirectory()) {
|
|
26
26
|
try {
|
|
27
|
-
return fs.readdirSync(
|
|
27
|
+
return fs.readdirSync(file);
|
|
28
28
|
}
|
|
29
29
|
catch (err) {
|
|
30
|
-
throw new Error(i18n.__('languageAnalysisProjectRootFileNameReadError',
|
|
30
|
+
throw new Error(i18n.__('languageAnalysisProjectRootFileNameReadError', file) +
|
|
31
31
|
`${err.message}`);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
if (projectStats.isFile()) {
|
|
35
|
-
return [path.basename(
|
|
35
|
+
return [path.basename(file)];
|
|
36
36
|
}
|
|
37
|
-
throw new Error(i18n.__('languageAnalysisProjectRootFileNameMissingError'),
|
|
37
|
+
throw new Error(i18n.__('languageAnalysisProjectRootFileNameMissingError'), file);
|
|
38
38
|
};
|
|
39
39
|
exports.getProjectRootFilenames = getProjectRootFilenames;
|
|
@@ -9,9 +9,9 @@ const checkIdentifiedLanguageHasProjectFile = require('./checkIdentifiedLanguage
|
|
|
9
9
|
const checkIdentifiedLanguageHasLockFile = require('./checkIdentifiedLanguageHasLockFile');
|
|
10
10
|
const getIdentifiedLanguageInfo = require('./getIdentifiedLanguageInfo');
|
|
11
11
|
const { libraryAnalysisError } = require('../../common/errorHandling');
|
|
12
|
-
module.exports = exports = (
|
|
12
|
+
module.exports = exports = (file, callback, appId, config) => {
|
|
13
13
|
const ae = new AnalysisEngine({
|
|
14
|
-
|
|
14
|
+
file,
|
|
15
15
|
appId,
|
|
16
16
|
languageAnalysis: { appId: appId },
|
|
17
17
|
config
|
|
@@ -10,12 +10,9 @@ const phpAE = require('../phpAnalysisEngine');
|
|
|
10
10
|
const goAE = require('../goAnalysisEngine');
|
|
11
11
|
const { vulnerabilityReport } = require('./report/reportingFeature');
|
|
12
12
|
const { newSendSnapShot } = require('../languageAnalysisEngine/sendSnapshot');
|
|
13
|
-
const
|
|
14
|
-
const chalk = require('chalk');
|
|
15
|
-
const saveFile = require('../../commands/audit/saveFile').default;
|
|
16
|
-
const generateSbom = require('../../sbom/generateSbom').default;
|
|
17
|
-
const { failSpinner, returnOra, startSpinner, succeedSpinner } = require('../../utils/oraWrapper');
|
|
13
|
+
const { returnOra, startSpinner, succeedSpinner } = require('../../utils/oraWrapper');
|
|
18
14
|
const { pollForSnapshotCompletition } = require('./sendSnapshot');
|
|
15
|
+
const auditSave = require('../save');
|
|
19
16
|
module.exports = exports = (err, analysis) => {
|
|
20
17
|
const { identifiedLanguageInfo } = analysis.languageAnalysis;
|
|
21
18
|
const catalogueAppId = analysis.languageAnalysis.appId;
|
|
@@ -40,10 +37,10 @@ module.exports = exports = (err, analysis) => {
|
|
|
40
37
|
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
|
|
41
38
|
startSpinner(reportSpinner);
|
|
42
39
|
const snapshotResponse = await newSendSnapShot(analysis, catalogueAppId);
|
|
43
|
-
|
|
44
|
-
succeedSpinner(reportSpinner, '
|
|
40
|
+
await pollForSnapshotCompletition(analysis.config, snapshotResponse.id, reportSpinner);
|
|
41
|
+
succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
|
|
45
42
|
await vulnerabilityReport(analysis, catalogueAppId, snapshotResponse.id);
|
|
46
|
-
await auditSave(config);
|
|
43
|
+
await auditSave.auditSave(config);
|
|
47
44
|
};
|
|
48
45
|
if (identifiedLanguageInfo.language === DOTNET) {
|
|
49
46
|
dotnetAE(identifiedLanguageInfo, analysis.config, langCallback);
|
|
@@ -67,23 +64,3 @@ module.exports = exports = (err, analysis) => {
|
|
|
67
64
|
goAE(identifiedLanguageInfo, analysis.config, langCallback);
|
|
68
65
|
}
|
|
69
66
|
};
|
|
70
|
-
async function auditSave(config) {
|
|
71
|
-
if (config.save) {
|
|
72
|
-
if (config.save.toLowerCase() === 'sbom') {
|
|
73
|
-
saveFile(config, await generateSbom(config));
|
|
74
|
-
const filename = `${config.applicationId}-sbom-cyclonedx.json`;
|
|
75
|
-
if (fs.existsSync(filename)) {
|
|
76
|
-
console.log(i18n.__('auditSBOMSaveSuccess') + ` - ${filename}`);
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
console.log(chalk.yellow.bold(`\n Unable to save ${filename} Software Bill of Materials (SBOM)`));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
console.log(i18n.__('auditBadFiletypeSpecifiedForSave'));
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
else if (config.save === null) {
|
|
87
|
-
console.log(i18n.__('auditNoFiletypeSpecifiedForSave'));
|
|
88
|
-
}
|
|
89
|
-
}
|
|
@@ -36,7 +36,7 @@ const deduceLanguageScaAnalysis = filenames => {
|
|
|
36
36
|
}
|
|
37
37
|
if (isNodeProjectFilename(filename)) {
|
|
38
38
|
deducedLanguages.push(filename);
|
|
39
|
-
language =
|
|
39
|
+
language = JAVASCRIPT;
|
|
40
40
|
}
|
|
41
41
|
if (isRubyProjectFilename(filename)) {
|
|
42
42
|
deducedLanguages.push(filename);
|
|
@@ -46,9 +46,16 @@ const deduceLanguageScaAnalysis = filenames => {
|
|
|
46
46
|
deducedLanguages.push(filename);
|
|
47
47
|
language = PYTHON;
|
|
48
48
|
}
|
|
49
|
+
if (isPhpProjectFilename(filename)) {
|
|
50
|
+
deducedLanguages.push({ language: PHP, projectFilename: filename });
|
|
51
|
+
language = PHP;
|
|
52
|
+
}
|
|
49
53
|
if (isNodeLockFilename(filename)) {
|
|
50
54
|
deducedLanguages.push(filename);
|
|
51
|
-
language =
|
|
55
|
+
language = JAVASCRIPT;
|
|
56
|
+
}
|
|
57
|
+
if (isPhpLockFilename(filename)) {
|
|
58
|
+
deducedLanguages.push({ language: PHP, lockFilename: filename });
|
|
52
59
|
}
|
|
53
60
|
if (isGoProjectFilename(filename)) {
|
|
54
61
|
deducedLanguages.push({ language: GO, projectFilename: filename });
|
|
@@ -115,13 +122,13 @@ const reduceIdentifiedLanguages = identifiedLanguages => identifiedLanguages.red
|
|
|
115
122
|
return accumulator;
|
|
116
123
|
}, {});
|
|
117
124
|
module.exports = exports = (analysis, next) => {
|
|
118
|
-
const {
|
|
125
|
+
const { file, languageAnalysis, config } = analysis;
|
|
119
126
|
let identifiedLanguages = languageAnalysis.projectRootFilenames.reduce((accumulator, filename) => {
|
|
120
127
|
const deducedLanguages = deduceLanguage(filename);
|
|
121
128
|
return [...accumulator, ...deducedLanguages];
|
|
122
129
|
}, []);
|
|
123
130
|
if (Object.keys(identifiedLanguages).length === 0) {
|
|
124
|
-
next(new Error(i18n.__('languageAnalysisNoLanguage',
|
|
131
|
+
next(new Error(i18n.__('languageAnalysisNoLanguage', file)));
|
|
125
132
|
return;
|
|
126
133
|
}
|
|
127
134
|
let language = config.language;
|
|
@@ -11,10 +11,11 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
11
11
|
const reportUtils_1 = require("./utils/reportUtils");
|
|
12
12
|
const severityCountModel_1 = require("./models/severityCountModel");
|
|
13
13
|
const reportOutputModel_1 = require("./models/reportOutputModel");
|
|
14
|
+
const constants_1 = require("../../../constants/constants");
|
|
14
15
|
const createLibraryHeader = (id, numberOfVulnerableLibraries, numberOfCves) => {
|
|
15
16
|
numberOfVulnerableLibraries === 1
|
|
16
|
-
? console.log(`
|
|
17
|
-
: console.log(`
|
|
17
|
+
? console.log(`Found 1 vulnerable library containing ${numberOfCves} CVEs`)
|
|
18
|
+
: console.log(`Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVEs `);
|
|
18
19
|
};
|
|
19
20
|
exports.createLibraryHeader = createLibraryHeader;
|
|
20
21
|
const getReport = async (config, reportId) => {
|
|
@@ -26,10 +27,6 @@ const getReport = async (config, reportId) => {
|
|
|
26
27
|
return res.body;
|
|
27
28
|
}
|
|
28
29
|
else {
|
|
29
|
-
console.log('config-------------------');
|
|
30
|
-
console.log(config);
|
|
31
|
-
console.log('reportId----------------');
|
|
32
|
-
console.log(reportId);
|
|
33
30
|
console.log(JSON.stringify(res));
|
|
34
31
|
(0, commonApi_1.handleResponseErrors)(res, 'report');
|
|
35
32
|
}
|
|
@@ -52,13 +49,20 @@ const printFormattedOutput = (libraries, config) => {
|
|
|
52
49
|
const report = new reportListModel_1.ReportList();
|
|
53
50
|
for (const library of libraries) {
|
|
54
51
|
const { name, version } = (0, reportUtils_1.findNameAndVersion)(library, config);
|
|
55
|
-
const newOutputModel = new reportListModel_1.ReportModelStructure(new reportListModel_1.ReportCompositeKey(name, version, (0, reportUtils_1.findHighestSeverityCVE)(library.cveArray)), library.cveArray);
|
|
52
|
+
const newOutputModel = new reportListModel_1.ReportModelStructure(new reportListModel_1.ReportCompositeKey(name, version, (0, reportUtils_1.findHighestSeverityCVE)(library.cveArray), (0, reportUtils_1.severityCountAllCVEs)(library.cveArray, new severityCountModel_1.SeverityCountModel()).getTotal), library.cveArray);
|
|
56
53
|
report.reportOutputList.push(newOutputModel);
|
|
57
54
|
}
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
const outputOrderedByLowestSeverityAndLowestNumOfCvesFirst = (0, lodash_1.orderBy)(report.reportOutputList, [
|
|
56
|
+
(reportListItem) => {
|
|
57
|
+
return reportListItem.compositeKey.highestSeverity.priority;
|
|
58
|
+
},
|
|
59
|
+
(reportListItem) => {
|
|
60
|
+
return reportListItem.compositeKey.numberOfSeverities;
|
|
61
|
+
}
|
|
62
|
+
], ['desc']);
|
|
63
|
+
let contrastHeaderNumCounter = outputOrderedByLowestSeverityAndLowestNumOfCvesFirst.length + 1;
|
|
64
|
+
for (const reportModel of outputOrderedByLowestSeverityAndLowestNumOfCvesFirst) {
|
|
65
|
+
contrastHeaderNumCounter--;
|
|
62
66
|
const { libraryName, libraryVersion, highestSeverity } = reportModel.compositeKey;
|
|
63
67
|
const numOfCVEs = reportModel.cveArray.length;
|
|
64
68
|
const header = buildHeader(highestSeverity, contrastHeaderNumCounter, libraryName, libraryVersion, numOfCVEs);
|
|
@@ -66,12 +70,16 @@ const printFormattedOutput = (libraries, config) => {
|
|
|
66
70
|
const reportOutputModel = new reportOutputModel_1.ReportOutputModel(header, body);
|
|
67
71
|
console.log(reportOutputModel.header.vulnMessage, reportOutputModel.header.introducesMessage);
|
|
68
72
|
console.log(reportOutputModel.body.issueMessage);
|
|
69
|
-
console.log(reportOutputModel.body.adviceMessage);
|
|
73
|
+
console.log(reportOutputModel.body.adviceMessage + '\n');
|
|
74
|
+
}
|
|
75
|
+
const { criticalMessage, highMessage, mediumMessage, lowMessage, noteMessage, total } = buildFooter(libraries);
|
|
76
|
+
if (total > 1) {
|
|
77
|
+
console.log(`${criticalMessage} | ${highMessage} | ${mediumMessage} | ${lowMessage} | ${noteMessage}`);
|
|
70
78
|
}
|
|
71
79
|
};
|
|
72
80
|
exports.printFormattedOutput = printFormattedOutput;
|
|
73
81
|
function buildHeader(highestSeverity, contrastHeaderNum, libraryName, version, numOfCVEs) {
|
|
74
|
-
const vulnerabilityPluralised = numOfCVEs > 1 ? '
|
|
82
|
+
const vulnerabilityPluralised = numOfCVEs > 1 ? 'vulnerabilities' : 'vulnerability';
|
|
75
83
|
const formattedHeaderNum = buildFormattedHeaderNum(contrastHeaderNum);
|
|
76
84
|
const vulnMessage = chalk_1.default
|
|
77
85
|
.hex(highestSeverity.outputColour)
|
|
@@ -96,6 +104,24 @@ function buildBody(cveArray) {
|
|
|
96
104
|
return new reportOutputModel_1.ReportOutputBodyModel(issueMessage, adviceMessage);
|
|
97
105
|
}
|
|
98
106
|
exports.buildBody = buildBody;
|
|
107
|
+
const buildFooter = (libraries) => {
|
|
108
|
+
const { critical, high, medium, low, note, getTotal } = (0, reportUtils_1.severityCountAllLibraries)(libraries);
|
|
109
|
+
const criticalMessage = chalk_1.default
|
|
110
|
+
.hex(constants_1.CRITICAL_COLOUR)
|
|
111
|
+
.bold(`${critical} Critical`);
|
|
112
|
+
const highMessage = chalk_1.default.hex(constants_1.HIGH_COLOUR).bold(`${high} High`);
|
|
113
|
+
const mediumMessage = chalk_1.default.hex(constants_1.MEDIUM_COLOUR).bold(`${medium} Medium`);
|
|
114
|
+
const lowMessage = chalk_1.default.hex(constants_1.LOW_COLOUR).bold(`${low} Low`);
|
|
115
|
+
const noteMessage = chalk_1.default.hex(constants_1.NOTE_COLOUR).bold(`${note} Note`);
|
|
116
|
+
return {
|
|
117
|
+
criticalMessage,
|
|
118
|
+
highMessage,
|
|
119
|
+
mediumMessage,
|
|
120
|
+
lowMessage,
|
|
121
|
+
noteMessage,
|
|
122
|
+
total: getTotal
|
|
123
|
+
};
|
|
124
|
+
};
|
|
99
125
|
function buildFormattedHeaderNum(contrastHeaderNum) {
|
|
100
126
|
let formattedHeaderNum;
|
|
101
127
|
if (contrastHeaderNum < 10) {
|
|
@@ -15,10 +15,11 @@ class ReportModelStructure {
|
|
|
15
15
|
}
|
|
16
16
|
exports.ReportModelStructure = ReportModelStructure;
|
|
17
17
|
class ReportCompositeKey {
|
|
18
|
-
constructor(libraryName, libraryVersion, highestSeverity) {
|
|
18
|
+
constructor(libraryName, libraryVersion, highestSeverity, numberOfSeverities) {
|
|
19
19
|
this.libraryName = libraryName;
|
|
20
20
|
this.libraryVersion = libraryVersion;
|
|
21
21
|
this.highestSeverity = highestSeverity;
|
|
22
|
+
this.numberOfSeverities = numberOfSeverities;
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
exports.ReportCompositeKey = ReportCompositeKey;
|
|
@@ -1,28 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatVulnerabilityOutput = exports.vulnerabilityReport = void 0;
|
|
6
|
+
exports.vulnerabilityReportV2 = exports.formatVulnerabilityOutput = exports.vulnerabilityReport = void 0;
|
|
4
7
|
const commonReportingFunctions_1 = require("./commonReportingFunctions");
|
|
5
8
|
const reportUtils_1 = require("./utils/reportUtils");
|
|
9
|
+
const i18n_1 = __importDefault(require("i18n"));
|
|
10
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
6
11
|
async function vulnerabilityReport(analysis, applicationId, reportId) {
|
|
7
12
|
const reportResponse = await (0, commonReportingFunctions_1.getReport)(analysis.config, reportId);
|
|
8
13
|
if (reportResponse !== undefined) {
|
|
9
14
|
const id = applicationId;
|
|
10
|
-
|
|
11
|
-
formatVulnerabilityOutput(reportResponse.vulnerabilities, id, name, analysis.config);
|
|
15
|
+
formatVulnerabilityOutput(reportResponse.vulnerabilities, id, analysis.config);
|
|
12
16
|
}
|
|
13
17
|
}
|
|
14
18
|
exports.vulnerabilityReport = vulnerabilityReport;
|
|
15
|
-
function formatVulnerabilityOutput(libraryVulnerabilityResponse, id,
|
|
16
|
-
const vulnerableLibraries = (0, reportUtils_1.
|
|
19
|
+
function formatVulnerabilityOutput(libraryVulnerabilityResponse, id, config) {
|
|
20
|
+
const vulnerableLibraries = (0, reportUtils_1.convertGenericToTypedLibraryVulns)(libraryVulnerabilityResponse);
|
|
17
21
|
const numberOfVulnerableLibraries = vulnerableLibraries.length;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
if (numberOfVulnerableLibraries === 0) {
|
|
23
|
+
console.log(i18n_1.default.__('scanNoVulnerabilitiesFound'));
|
|
24
|
+
console.log(i18n_1.default.__('scanNoVulnerabilitiesFoundSecureCode'));
|
|
25
|
+
console.log(i18n_1.default.__('scanNoVulnerabilitiesFoundGoodWork'));
|
|
26
|
+
console.log(chalk_1.default.bold(`Found ${numberOfVulnerableLibraries} vulnerabilities`));
|
|
27
|
+
console.log(i18n_1.default.__('foundDetailedVulnerabilities', String(0), String(0), String(0), String(0), String(0)));
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
let numberOfCves = 0;
|
|
31
|
+
vulnerableLibraries.forEach(lib => (numberOfCves += lib.cveArray.length));
|
|
32
|
+
(0, commonReportingFunctions_1.createLibraryHeader)(id, numberOfVulnerableLibraries, numberOfCves);
|
|
33
|
+
const hasSomeVulnerabilitiesReported = (0, commonReportingFunctions_1.printVulnerabilityResponse)(vulnerableLibraries, config);
|
|
34
|
+
return [
|
|
35
|
+
hasSomeVulnerabilitiesReported,
|
|
36
|
+
numberOfCves,
|
|
37
|
+
(0, reportUtils_1.severityCountAllLibraries)(vulnerableLibraries)
|
|
38
|
+
];
|
|
39
|
+
}
|
|
27
40
|
}
|
|
28
41
|
exports.formatVulnerabilityOutput = formatVulnerabilityOutput;
|
|
42
|
+
async function vulnerabilityReportV2(config, reportId) {
|
|
43
|
+
const reportResponse = await (0, commonReportingFunctions_1.getReport)(config, reportId);
|
|
44
|
+
if (reportResponse !== undefined) {
|
|
45
|
+
const name = config.applicationName;
|
|
46
|
+
formatVulnerabilityOutput(reportResponse.vulnerabilities, config.applicationId, config);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.vulnerabilityReportV2 = vulnerabilityReportV2;
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.findNameAndVersion = exports.severityCountSingleCVE = exports.severityCountAllCVEs = exports.severityCountAllLibraries = exports.
|
|
6
|
+
exports.findNameAndVersion = exports.severityCountSingleCVE = exports.severityCountAllCVEs = exports.severityCountAllLibraries = exports.convertGenericToTypedLibraryVulns = exports.findCVESeverity = exports.findCVESeveritiesAndOrderByHighestPriority = exports.findHighestSeverityCVE = void 0;
|
|
7
7
|
const reportLibraryModel_1 = require("../models/reportLibraryModel");
|
|
8
8
|
const reportSeverityModel_1 = require("../models/reportSeverityModel");
|
|
9
9
|
const constants_1 = __importDefault(require("../../../languageAnalysisEngine/constants"));
|
|
@@ -40,12 +40,12 @@ function findCVESeverity(cve) {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
exports.findCVESeverity = findCVESeverity;
|
|
43
|
-
function
|
|
43
|
+
function convertGenericToTypedLibraryVulns(libraries) {
|
|
44
44
|
return Object.entries(libraries).map(([name, cveArray]) => {
|
|
45
45
|
return new reportLibraryModel_1.ReportLibraryModel(name, cveArray);
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
|
-
exports.
|
|
48
|
+
exports.convertGenericToTypedLibraryVulns = convertGenericToTypedLibraryVulns;
|
|
49
49
|
function severityCountAllLibraries(vulnerableLibraries) {
|
|
50
50
|
const severityCount = new severityCountModel_1.SeverityCountModel();
|
|
51
51
|
vulnerableLibraries.forEach(lib => severityCountAllCVEs(lib.cveArray, severityCount));
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const i18n = require('i18n');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const save = require('../commands/audit/saveFile');
|
|
6
|
+
const sbom = require('../sbom/generateSbom');
|
|
7
|
+
async function auditSave(config) {
|
|
8
|
+
if (config.save) {
|
|
9
|
+
if (config.save.toLowerCase() === 'sbom') {
|
|
10
|
+
save.saveFile(config, await sbom.generateSbom(config));
|
|
11
|
+
const filename = `${config.applicationId}-sbom-cyclonedx.json`;
|
|
12
|
+
if (fs.existsSync(filename)) {
|
|
13
|
+
console.log(i18n.__('auditSBOMSaveSuccess') + ` - ${filename}`);
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
console.log(chalk.yellow.bold(`\n Unable to save ${filename} Software Bill of Materials (SBOM)`));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
console.log(i18n.__('auditBadFiletypeSpecifiedForSave'));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else if (config.save === null) {
|
|
24
|
+
console.log(i18n.__('auditNoFiletypeSpecifiedForSave'));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
module.exports = {
|
|
28
|
+
auditSave
|
|
29
|
+
};
|
|
@@ -3,12 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.startAudit = exports.dealWithNoAppId = void 0;
|
|
6
|
+
exports.getAppName = exports.startAudit = exports.dealWithNoAppId = void 0;
|
|
7
7
|
const catalogueApplication_1 = require("../../audit/catalogueApplication/catalogueApplication");
|
|
8
8
|
const commonApi_1 = __importDefault(require("../../audit/languageAnalysisEngine/commonApi"));
|
|
9
9
|
const identifyLanguageAE = require('./../../audit/languageAnalysisEngine');
|
|
10
10
|
const languageFactory = require('../../audit/languageAnalysisEngine/languageAnalysisFactory');
|
|
11
|
-
const { v4: uuidv4 } = require('uuid');
|
|
12
11
|
const dealWithNoAppId = async (config) => {
|
|
13
12
|
let appID;
|
|
14
13
|
try {
|
|
@@ -17,8 +16,11 @@ const dealWithNoAppId = async (config) => {
|
|
|
17
16
|
return await (0, catalogueApplication_1.catalogueApplication)(config);
|
|
18
17
|
}
|
|
19
18
|
if (!appID && !config.applicationName) {
|
|
20
|
-
config.applicationName =
|
|
21
|
-
|
|
19
|
+
config.applicationName = (0, exports.getAppName)(config.file);
|
|
20
|
+
appID = await commonApi_1.default.returnAppId(config);
|
|
21
|
+
if (!appID) {
|
|
22
|
+
return await (0, catalogueApplication_1.catalogueApplication)(config);
|
|
23
|
+
}
|
|
22
24
|
}
|
|
23
25
|
}
|
|
24
26
|
catch (e) {
|
|
@@ -35,6 +37,20 @@ const startAudit = async (config) => {
|
|
|
35
37
|
if (!config.applicationId) {
|
|
36
38
|
config.applicationId = await (0, exports.dealWithNoAppId)(config);
|
|
37
39
|
}
|
|
38
|
-
identifyLanguageAE(config.
|
|
40
|
+
identifyLanguageAE(config.file, languageFactory, config.applicationId, config);
|
|
39
41
|
};
|
|
40
42
|
exports.startAudit = startAudit;
|
|
43
|
+
const getAppName = (file) => {
|
|
44
|
+
const last = file.charAt(file.length - 1);
|
|
45
|
+
if (last !== '/') {
|
|
46
|
+
return file.split('/').pop();
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const str = removeLastChar(file);
|
|
50
|
+
return str.split('/').pop();
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
exports.getAppName = getAppName;
|
|
54
|
+
const removeLastChar = (str) => {
|
|
55
|
+
return str.substring(0, str.length - 1);
|
|
56
|
+
};
|
|
@@ -46,7 +46,30 @@ const auditUsageGuide = (0, command_line_usage_1.default)([
|
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
header: i18n_1.default.__('constantsAuditOptions'),
|
|
49
|
-
optionList: constants_1.default.commandLineDefinitions.auditOptionDefinitions
|
|
49
|
+
optionList: constants_1.default.commandLineDefinitions.auditOptionDefinitions,
|
|
50
|
+
hide: [
|
|
51
|
+
'application-id',
|
|
52
|
+
'application-name',
|
|
53
|
+
'organization-id',
|
|
54
|
+
'api-key',
|
|
55
|
+
'authorization',
|
|
56
|
+
'host',
|
|
57
|
+
'proxy',
|
|
58
|
+
'help',
|
|
59
|
+
'ff',
|
|
60
|
+
'ignore-cert-errors',
|
|
61
|
+
'verbose',
|
|
62
|
+
'debug',
|
|
63
|
+
'experimental',
|
|
64
|
+
'tags',
|
|
65
|
+
'sub-project',
|
|
66
|
+
'code',
|
|
67
|
+
'maven-settings-path',
|
|
68
|
+
'language',
|
|
69
|
+
'experimental',
|
|
70
|
+
'app-groups',
|
|
71
|
+
'metadata'
|
|
72
|
+
]
|
|
50
73
|
}
|
|
51
74
|
]);
|
|
52
75
|
exports.auditUsageGuide = auditUsageGuide;
|
|
@@ -4,13 +4,19 @@ exports.processAudit = void 0;
|
|
|
4
4
|
const auditController_1 = require("./auditController");
|
|
5
5
|
const auditConfig_1 = require("./auditConfig");
|
|
6
6
|
const help_1 = require("./help");
|
|
7
|
+
const scaAnalysis_1 = require("../scan/sca/scaAnalysis");
|
|
7
8
|
const processAudit = async (argv) => {
|
|
8
9
|
if (argv.indexOf('--help') != -1) {
|
|
9
10
|
printHelpMessage();
|
|
10
11
|
process.exit(0);
|
|
11
12
|
}
|
|
12
13
|
const config = (0, auditConfig_1.getAuditConfig)(argv);
|
|
13
|
-
|
|
14
|
+
if (config.experimental) {
|
|
15
|
+
await (0, scaAnalysis_1.processSca)(config);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
await (0, auditController_1.startAudit)(config);
|
|
19
|
+
}
|
|
14
20
|
};
|
|
15
21
|
exports.processAudit = processAudit;
|
|
16
22
|
const printHelpMessage = () => {
|
|
@@ -3,9 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.saveFile = void 0;
|
|
6
7
|
const fs_1 = __importDefault(require("fs"));
|
|
7
|
-
|
|
8
|
+
const saveFile = (config, rawResults) => {
|
|
8
9
|
const fileName = `${config.applicationId}-sbom-cyclonedx.json`;
|
|
9
10
|
fs_1.default.writeFileSync(fileName, JSON.stringify(rawResults));
|
|
10
|
-
}
|
|
11
|
-
exports.
|
|
11
|
+
};
|
|
12
|
+
exports.saveFile = saveFile;
|
|
13
|
+
module.exports = {
|
|
14
|
+
saveFile: exports.saveFile
|
|
15
|
+
};
|