@contrast/contrast 1.0.19 → 1.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/report/commonReportingFunctions.js +3 -4
- package/dist/audit/report/models/reportListModel.js +2 -1
- package/dist/audit/report/reportingFeature.js +1 -1
- package/dist/audit/report/utils/reportUtils.js +30 -11
- package/dist/cliConstants.js +13 -6
- package/dist/commands/audit/auditConfig.js +1 -2
- package/dist/commands/audit/help.js +2 -1
- package/dist/commands/audit/processAudit.js +1 -1
- package/dist/commands/fingerprint/fingerprintConfig.js +12 -0
- package/dist/commands/fingerprint/processFingerprint.js +14 -0
- package/dist/commands/learn/learn.js +9 -0
- package/dist/commands/learn/processLearn.js +10 -0
- package/dist/common/commonHelp.js +8 -1
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +14 -3
- package/dist/index.js +8 -0
- package/dist/lambda/help.js +2 -1
- package/dist/scaAnalysis/common/auditReport.js +16 -60
- package/dist/scaAnalysis/common/commonReportingFunctionsSca.js +154 -0
- package/dist/scaAnalysis/common/models/ScaReportModel.js +45 -0
- package/dist/scaAnalysis/common/scaServicesUpload.js +4 -3
- package/dist/scaAnalysis/common/utils/reportUtilsSca.js +76 -0
- package/dist/scaAnalysis/java/analysis.js +1 -28
- package/dist/scaAnalysis/java/index.js +1 -13
- package/dist/scaAnalysis/scaAnalysis.js +155 -0
- package/dist/scan/autoDetection.js +2 -2
- package/dist/scan/fileUtils.js +2 -2
- package/dist/scan/formatScanOutput.js +19 -13
- package/dist/scan/help.js +2 -1
- package/dist/utils/paramsUtil/configStoreParams.js +1 -12
- package/dist/utils/paramsUtil/paramHandler.js +1 -7
- package/package.json +5 -1
- package/src/audit/report/commonReportingFunctions.js +7 -5
- package/src/audit/report/models/reportListModel.ts +12 -2
- package/src/audit/report/reportingFeature.ts +1 -1
- package/src/audit/report/utils/reportUtils.ts +4 -4
- package/src/cliConstants.js +15 -6
- package/src/commands/audit/auditConfig.js +1 -2
- package/src/commands/audit/help.js +2 -1
- package/src/commands/audit/processAudit.js +1 -1
- package/src/commands/fingerprint/fingerprintConfig.js +19 -0
- package/src/commands/fingerprint/processFingerprint.js +21 -0
- package/src/commands/learn/learn.js +10 -0
- package/src/commands/learn/processLearn.js +13 -0
- package/src/common/commonHelp.js +11 -1
- package/src/constants/constants.js +1 -1
- package/src/constants/locales.js +22 -3
- package/src/index.ts +11 -0
- package/src/lambda/help.ts +2 -1
- package/src/scaAnalysis/common/auditReport.js +25 -80
- package/src/scaAnalysis/common/commonReportingFunctionsSca.js +276 -0
- package/src/scaAnalysis/common/models/ScaReportModel.ts +81 -0
- package/src/scaAnalysis/common/scaServicesUpload.js +5 -3
- package/src/scaAnalysis/common/utils/reportUtilsSca.ts +123 -0
- package/src/scaAnalysis/java/analysis.js +1 -28
- package/src/scaAnalysis/java/index.js +1 -18
- package/src/scaAnalysis/scaAnalysis.js +206 -0
- package/src/scan/autoDetection.js +2 -2
- package/src/scan/fileUtils.js +2 -2
- package/src/scan/formatScanOutput.ts +28 -17
- package/src/scan/help.js +2 -1
- package/src/utils/getConfig.ts +0 -1
- package/src/utils/paramsUtil/configStoreParams.js +1 -14
- package/src/utils/paramsUtil/paramHandler.js +1 -9
- package/dist/commands/scan/sca/scaAnalysis.js +0 -155
- package/src/commands/scan/sca/scaAnalysis.js +0 -206
|
@@ -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
|
-
|
|
47
|
+
const reportBody = res.body;
|
|
48
|
+
return { reportBody, reportID };
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
51
|
});
|
|
51
52
|
if (!keepChecking) {
|
|
52
|
-
return
|
|
53
|
+
return { reportArray: res.reportBody, reportID };
|
|
53
54
|
}
|
|
54
55
|
await requestUtils.sleep(5000);
|
|
55
56
|
}
|
|
56
|
-
return
|
|
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
|
};
|
|
@@ -3,13 +3,10 @@ const analysis = require('./analysis');
|
|
|
3
3
|
const { parseBuildDeps } = require('./javaBuildDepsParser');
|
|
4
4
|
const { createJavaTSMessage } = require('../common/formatMessage');
|
|
5
5
|
const { parseDependenciesForSCAServices } = require('../common/scaParserForGoAndJava');
|
|
6
|
-
const chalk = require('chalk');
|
|
7
|
-
const _ = require('lodash');
|
|
8
6
|
const javaAnalysis = async (config, languageFiles) => {
|
|
9
7
|
languageFiles.JAVA.forEach(file => {
|
|
10
8
|
file.replace('build.gradle.kts', 'build.gradle');
|
|
11
9
|
});
|
|
12
|
-
await getAgreement(config);
|
|
13
10
|
const javaDeps = buildJavaTree(config, languageFiles.JAVA);
|
|
14
11
|
if (config.experimental) {
|
|
15
12
|
return parseDependenciesForSCAServices(javaDeps);
|
|
@@ -18,19 +15,10 @@ const javaAnalysis = async (config, languageFiles) => {
|
|
|
18
15
|
return createJavaTSMessage(javaDeps);
|
|
19
16
|
}
|
|
20
17
|
};
|
|
21
|
-
const getAgreement = async (config) => {
|
|
22
|
-
console.log(chalk.bold('Java project detected'));
|
|
23
|
-
console.log('Java analysis uses maven / gradle which are potentially susceptible to command injection. Be sure that the code you are running Contrast CLI on is trusted before continuing.');
|
|
24
|
-
if (!process.env.CI && !config?.javaAgreement) {
|
|
25
|
-
return await analysis.agreementPrompt(config);
|
|
26
|
-
}
|
|
27
|
-
return config;
|
|
28
|
-
};
|
|
29
18
|
const buildJavaTree = (config, files) => {
|
|
30
19
|
const javaBuildDeps = analysis.getJavaBuildDeps(config, files);
|
|
31
20
|
return parseBuildDeps(config, javaBuildDeps);
|
|
32
21
|
};
|
|
33
22
|
module.exports = {
|
|
34
|
-
javaAnalysis
|
|
35
|
-
getAgreement
|
|
23
|
+
javaAnalysis
|
|
36
24
|
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const { supportedLanguages: { JAVA, GO, PYTHON, RUBY, JAVASCRIPT, NODE, PHP, DOTNET } } = require('../constants/constants');
|
|
3
|
+
const { pollForSnapshotCompletion } = require('../audit/languageAnalysisEngine/sendSnapshot');
|
|
4
|
+
const { returnOra, startSpinner, succeedSpinner } = require('../utils/oraWrapper');
|
|
5
|
+
const { vulnerabilityReportV2 } = require('../audit/report/reportingFeature');
|
|
6
|
+
const autoDetection = require('../scan/autoDetection');
|
|
7
|
+
const treeUpload = require('./common/treeUpload');
|
|
8
|
+
const auditController = require('../commands/audit/auditController');
|
|
9
|
+
const rootFile = require('../audit/languageAnalysisEngine/getProjectRootFilenames');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const i18n = require('i18n');
|
|
12
|
+
const auditSave = require('../audit/save');
|
|
13
|
+
const { auditUsageGuide } = require('../commands/audit/help');
|
|
14
|
+
const repoMode = require('./repoMode');
|
|
15
|
+
const { dotNetAnalysis } = require('./dotnet');
|
|
16
|
+
const { goAnalysis } = require('./go/goAnalysis');
|
|
17
|
+
const { phpAnalysis } = require('./php');
|
|
18
|
+
const { rubyAnalysis } = require('./ruby');
|
|
19
|
+
const { pythonAnalysis } = require('./python');
|
|
20
|
+
const javaAnalysis = require('./java');
|
|
21
|
+
const jsAnalysis = require('./javascript');
|
|
22
|
+
const auditReport = require('./common/auditReport');
|
|
23
|
+
const scaUpload = require('./common/scaServicesUpload');
|
|
24
|
+
const settingsHelper = require('../utils/settingsHelper');
|
|
25
|
+
const chalk = require('chalk');
|
|
26
|
+
const saveResults = require('../scan/saveResults');
|
|
27
|
+
const { convertGenericToTypedReportModelSca } = require('./common/utils/reportUtilsSca');
|
|
28
|
+
const processSca = async (config) => {
|
|
29
|
+
config = await settingsHelper.getSettings(config);
|
|
30
|
+
const startTime = performance.now();
|
|
31
|
+
let filesFound;
|
|
32
|
+
if (config.help) {
|
|
33
|
+
console.log(auditUsageGuide);
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
const projectStats = await rootFile.getProjectStats(config.file);
|
|
37
|
+
let pathWithFile = projectStats.isFile();
|
|
38
|
+
config.fileName = config.file;
|
|
39
|
+
config.file = pathWithFile
|
|
40
|
+
? rootFile.getDirectoryFromPathGiven(config.file).concat('/')
|
|
41
|
+
: config.file;
|
|
42
|
+
filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config.file);
|
|
43
|
+
autoDetection.dealWithMultiJava(filesFound);
|
|
44
|
+
if (filesFound.length > 1 && pathWithFile) {
|
|
45
|
+
filesFound = filesFound.filter(i => Object.values(i)[0].includes(path.basename(config.fileName)));
|
|
46
|
+
}
|
|
47
|
+
let messageToSend = undefined;
|
|
48
|
+
if (filesFound.length === 1) {
|
|
49
|
+
switch (Object.keys(filesFound[0])[0]) {
|
|
50
|
+
case JAVA:
|
|
51
|
+
config.language = JAVA;
|
|
52
|
+
if (config.mode === 'repo') {
|
|
53
|
+
try {
|
|
54
|
+
return repoMode.buildRepo(config, filesFound[0]);
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
throw new Error('Unable to build in repository mode. Check your project file');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
messageToSend = await javaAnalysis.javaAnalysis(config, filesFound[0]);
|
|
62
|
+
}
|
|
63
|
+
break;
|
|
64
|
+
case JAVASCRIPT:
|
|
65
|
+
messageToSend = await jsAnalysis.jsAnalysis(config, filesFound[0]);
|
|
66
|
+
config.language = NODE;
|
|
67
|
+
break;
|
|
68
|
+
case PYTHON:
|
|
69
|
+
messageToSend = pythonAnalysis(config, filesFound[0]);
|
|
70
|
+
config.language = PYTHON;
|
|
71
|
+
break;
|
|
72
|
+
case RUBY:
|
|
73
|
+
messageToSend = rubyAnalysis(config, filesFound[0]);
|
|
74
|
+
config.language = RUBY;
|
|
75
|
+
break;
|
|
76
|
+
case PHP:
|
|
77
|
+
messageToSend = phpAnalysis(config, filesFound[0]);
|
|
78
|
+
config.language = PHP;
|
|
79
|
+
break;
|
|
80
|
+
case GO:
|
|
81
|
+
messageToSend = goAnalysis(config, filesFound[0]);
|
|
82
|
+
config.language = GO;
|
|
83
|
+
break;
|
|
84
|
+
case DOTNET:
|
|
85
|
+
if (config.experimental) {
|
|
86
|
+
console.log(`${chalk.bold('\n.NET project found\n')} Language type is unsupported.`);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
messageToSend = dotNetAnalysis(config, filesFound[0]);
|
|
91
|
+
config.language = DOTNET;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
default:
|
|
95
|
+
console.log('No supported language detected in project path');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!config.applicationId) {
|
|
99
|
+
config.applicationId = await auditController.dealWithNoAppId(config);
|
|
100
|
+
}
|
|
101
|
+
if (config.experimental) {
|
|
102
|
+
console.log('');
|
|
103
|
+
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
|
|
104
|
+
startSpinner(reportSpinner);
|
|
105
|
+
const { reportArray, reportId } = await scaUpload.scaTreeUpload(messageToSend, config);
|
|
106
|
+
const reportModelLibraryList = convertGenericToTypedReportModelSca(reportArray);
|
|
107
|
+
auditReport.processAuditReport(config, reportModelLibraryList);
|
|
108
|
+
succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
|
|
109
|
+
if (config.save !== undefined) {
|
|
110
|
+
await auditSave.auditSave(config, reportId);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
console.log('Use contrast audit --save to generate an SBOM');
|
|
114
|
+
}
|
|
115
|
+
const endTime = performance.now() - startTime;
|
|
116
|
+
const scanDurationMs = endTime - startTime;
|
|
117
|
+
console.log(`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
console.log('');
|
|
121
|
+
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
|
|
122
|
+
startSpinner(reportSpinner);
|
|
123
|
+
const snapshotResponse = await treeUpload.commonSendSnapShot(messageToSend, config);
|
|
124
|
+
await pollForSnapshotCompletion(config, snapshotResponse.id, reportSpinner);
|
|
125
|
+
succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
|
|
126
|
+
await vulnerabilityReportV2(config, snapshotResponse.id);
|
|
127
|
+
if (config.save !== undefined) {
|
|
128
|
+
await auditSave.auditSave(config);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
console.log('\nUse contrast audit --save to generate an SBOM');
|
|
132
|
+
}
|
|
133
|
+
const endTime = performance.now() - startTime;
|
|
134
|
+
const scanDurationMs = endTime - startTime;
|
|
135
|
+
console.log(`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
if (filesFound.length === 0) {
|
|
140
|
+
console.log(i18n.__('languageAnalysisNoLanguage'));
|
|
141
|
+
console.log(i18n.__('languageAnalysisNoLanguageHelpLine'));
|
|
142
|
+
throw new Error();
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
console.log(chalk.bold(`\nMultiple language files detected \n`));
|
|
146
|
+
filesFound.forEach(file => {
|
|
147
|
+
console.log(`${Object.keys(file)[0]} : `, Object.values(file)[0]);
|
|
148
|
+
});
|
|
149
|
+
throw new Error(`Please use --file to audit one language only. \nExample: contrast audit --file package-lock.json`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
module.exports = {
|
|
154
|
+
processSca
|
|
155
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const i18n = require('i18n');
|
|
3
3
|
const fileFinder = require('./fileUtils');
|
|
4
|
-
const autoDetectFingerprintInfo = async (filePath) => {
|
|
5
|
-
let complexObj = await fileFinder.findAllFiles(filePath);
|
|
4
|
+
const autoDetectFingerprintInfo = async (filePath, depth) => {
|
|
5
|
+
let complexObj = await fileFinder.findAllFiles(filePath, depth);
|
|
6
6
|
let result = [];
|
|
7
7
|
let count = 0;
|
|
8
8
|
complexObj.forEach(i => {
|
package/dist/scan/fileUtils.js
CHANGED
|
@@ -10,7 +10,7 @@ const findFile = async () => {
|
|
|
10
10
|
onlyFiles: true
|
|
11
11
|
});
|
|
12
12
|
};
|
|
13
|
-
const findAllFiles = async (filePath) => {
|
|
13
|
+
const findAllFiles = async (filePath, depth = 2) => {
|
|
14
14
|
const result = await fg([
|
|
15
15
|
'**/pom.xml',
|
|
16
16
|
'**/build.gradle',
|
|
@@ -22,7 +22,7 @@ const findAllFiles = async (filePath) => {
|
|
|
22
22
|
'**/go.mod'
|
|
23
23
|
], {
|
|
24
24
|
dot: false,
|
|
25
|
-
deep:
|
|
25
|
+
deep: depth,
|
|
26
26
|
onlyFiles: true,
|
|
27
27
|
absolute: true,
|
|
28
28
|
cwd: filePath ? filePath : process.cwd()
|
|
@@ -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.assignBySeverity = exports.stripTags = exports.getCodeFlowInfo = exports.getSourceLineNumber = exports.getLocationsSyncInfo = exports.editVulName = exports.getDefaultView = exports.formatLinks = exports.formatScanOutput = void 0;
|
|
6
|
+
exports.assignBySeverity = exports.stripTags = exports.getCodeFlowInfo = exports.getSourceLineNumber = exports.getLocationsSyncInfo = exports.editVulName = exports.doAddSourceLineNumber = exports.getDefaultView = exports.formatLinks = exports.formatScanOutput = void 0;
|
|
7
7
|
const i18n_1 = __importDefault(require("i18n"));
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
9
|
const groupedResultsModel_1 = require("./models/groupedResultsModel");
|
|
@@ -12,24 +12,25 @@ const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
|
12
12
|
const constants_1 = require("../constants/constants");
|
|
13
13
|
const commonReportingFunctions_1 = require("../audit/report/commonReportingFunctions");
|
|
14
14
|
function formatScanOutput(scanResults) {
|
|
15
|
-
const {
|
|
16
|
-
const
|
|
17
|
-
|
|
15
|
+
const { content } = scanResults.scanResultsInstances;
|
|
16
|
+
const { language } = scanResults.scanDetail;
|
|
17
|
+
const severityCounts = (0, commonReportingFunctions_1.getSeverityCounts)(content);
|
|
18
|
+
if (content.length === 0) {
|
|
18
19
|
console.log(i18n_1.default.__('scanNoVulnerabilitiesFound'));
|
|
19
20
|
console.log(i18n_1.default.__('scanNoVulnerabilitiesFoundSecureCode'));
|
|
20
21
|
console.log(i18n_1.default.__('scanNoVulnerabilitiesFoundGoodWork'));
|
|
21
22
|
}
|
|
22
23
|
else {
|
|
23
|
-
const message =
|
|
24
|
+
const message = severityCounts.critical || severityCounts.high
|
|
24
25
|
? 'Here are your top priorities to fix'
|
|
25
26
|
: "No major issues, here's what we found";
|
|
26
27
|
console.log(chalk_1.default.bold(message));
|
|
27
28
|
console.log();
|
|
28
|
-
|
|
29
|
+
const defaultView = getDefaultView(content, language);
|
|
29
30
|
let count = 0;
|
|
30
31
|
defaultView.forEach(entry => {
|
|
31
32
|
count++;
|
|
32
|
-
|
|
33
|
+
const table = new cli_table3_1.default({
|
|
33
34
|
chars: {
|
|
34
35
|
top: '',
|
|
35
36
|
'top-mid': '',
|
|
@@ -90,8 +91,8 @@ function formatScanOutput(scanResults) {
|
|
|
90
91
|
console.log();
|
|
91
92
|
});
|
|
92
93
|
}
|
|
93
|
-
(0, commonReportingFunctions_1.printVulnInfo)(
|
|
94
|
-
return
|
|
94
|
+
(0, commonReportingFunctions_1.printVulnInfo)(severityCounts);
|
|
95
|
+
return severityCounts;
|
|
95
96
|
}
|
|
96
97
|
exports.formatScanOutput = formatScanOutput;
|
|
97
98
|
function formatLinks(objName, entry) {
|
|
@@ -107,7 +108,7 @@ function formatLinks(objName, entry) {
|
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
110
|
exports.formatLinks = formatLinks;
|
|
110
|
-
function getDefaultView(content) {
|
|
111
|
+
function getDefaultView(content, language) {
|
|
111
112
|
const groupTypeResults = [];
|
|
112
113
|
content.forEach(resultEntry => {
|
|
113
114
|
const groupResultsObj = new groupedResultsModel_1.GroupedResultsModel(resultEntry.ruleId);
|
|
@@ -118,8 +119,7 @@ function getDefaultView(content) {
|
|
|
118
119
|
groupResultsObj.learn = resultEntry.learn;
|
|
119
120
|
groupResultsObj.message = resultEntry.message?.text
|
|
120
121
|
? editVulName(resultEntry.message.text) +
|
|
121
|
-
|
|
122
|
-
getSourceLineNumber(resultEntry)
|
|
122
|
+
doAddSourceLineNumber(resultEntry, language)
|
|
123
123
|
: '';
|
|
124
124
|
groupResultsObj.codePath = getLocationsSyncInfo(resultEntry);
|
|
125
125
|
groupTypeResults.push(groupResultsObj);
|
|
@@ -128,6 +128,12 @@ function getDefaultView(content) {
|
|
|
128
128
|
return (0, lodash_1.sortBy)(groupTypeResults, ['priority']);
|
|
129
129
|
}
|
|
130
130
|
exports.getDefaultView = getDefaultView;
|
|
131
|
+
function doAddSourceLineNumber(resultEntry, language) {
|
|
132
|
+
return language !== constants_1.supportedLanguagesScan.JAVASCRIPT
|
|
133
|
+
? ':' + getSourceLineNumber(resultEntry)
|
|
134
|
+
: '';
|
|
135
|
+
}
|
|
136
|
+
exports.doAddSourceLineNumber = doAddSourceLineNumber;
|
|
131
137
|
function editVulName(message) {
|
|
132
138
|
return message.substring(message.indexOf(' in '));
|
|
133
139
|
}
|
|
@@ -143,7 +149,7 @@ function getLocationsSyncInfo(resultEntry) {
|
|
|
143
149
|
exports.getLocationsSyncInfo = getLocationsSyncInfo;
|
|
144
150
|
function getSourceLineNumber(resultEntry) {
|
|
145
151
|
const locationsLineNumber = resultEntry.locations[0]?.physicalLocation?.region?.startLine || '';
|
|
146
|
-
|
|
152
|
+
const codeFlowLineNumber = getCodeFlowInfo(resultEntry);
|
|
147
153
|
return codeFlowLineNumber ? codeFlowLineNumber : locationsLineNumber;
|
|
148
154
|
}
|
|
149
155
|
exports.getSourceLineNumber = getSourceLineNumber;
|
package/dist/scan/help.js
CHANGED
|
@@ -43,7 +43,8 @@ const scanUsageGuide = commandLineUsage([
|
|
|
43
43
|
optionList: constants.commandLineDefinitions.scanAdvancedOptionDefinitionsForHelp
|
|
44
44
|
},
|
|
45
45
|
commonHelpLinks()[0],
|
|
46
|
-
commonHelpLinks()[1]
|
|
46
|
+
commonHelpLinks()[1],
|
|
47
|
+
commonHelpLinks()[2]
|
|
47
48
|
]);
|
|
48
49
|
module.exports = {
|
|
49
50
|
scanUsageGuide
|
|
@@ -15,15 +15,4 @@ const getAuth = () => {
|
|
|
15
15
|
}
|
|
16
16
|
return ContrastConfToUse;
|
|
17
17
|
};
|
|
18
|
-
|
|
19
|
-
const ContrastConf = config.localConfig(APP_NAME, APP_VERSION);
|
|
20
|
-
let ContrastConfToUse = {};
|
|
21
|
-
ContrastConfToUse.javaAgreement = ContrastConf.get('javaAgreement');
|
|
22
|
-
return ContrastConfToUse;
|
|
23
|
-
};
|
|
24
|
-
const setAgreement = agreement => {
|
|
25
|
-
const ContrastConf = config.localConfig(APP_NAME, APP_VERSION);
|
|
26
|
-
ContrastConf.set('javaAgreement', agreement);
|
|
27
|
-
return agreement;
|
|
28
|
-
};
|
|
29
|
-
module.exports = { getAuth, getAgreement, setAgreement };
|
|
18
|
+
module.exports = { getAuth };
|
|
@@ -22,10 +22,4 @@ const getAuth = params => {
|
|
|
22
22
|
process.exit(1);
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
|
-
|
|
26
|
-
return configStoreParams.getAgreement();
|
|
27
|
-
};
|
|
28
|
-
const setAgreement = answer => {
|
|
29
|
-
return configStoreParams.setAgreement(answer);
|
|
30
|
-
};
|
|
31
|
-
module.exports = { getAuth, getAgreement, setAgreement };
|
|
25
|
+
module.exports = { getAuth };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/contrast",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.21",
|
|
4
4
|
"description": "Contrast Security's command line tool",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
{
|
|
16
16
|
"name": "Andrew Shanks",
|
|
17
17
|
"email": "andrew.shanks@contrastsecurity.com"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "Oisín Cassidy",
|
|
21
|
+
"email": "oisin.cassidy@contrastsecurity.com"
|
|
18
22
|
}
|
|
19
23
|
],
|
|
20
24
|
"license": "ISC",
|
|
@@ -108,7 +108,8 @@ const printFormattedOutput = (
|
|
|
108
108
|
new SeverityCountModel()
|
|
109
109
|
).getTotal
|
|
110
110
|
),
|
|
111
|
-
library.cveArray
|
|
111
|
+
library.cveArray,
|
|
112
|
+
null
|
|
112
113
|
)
|
|
113
114
|
report.reportOutputList.push(newOutputModel)
|
|
114
115
|
}
|
|
@@ -131,6 +132,7 @@ const printFormattedOutput = (
|
|
|
131
132
|
contrastHeaderNumCounter++
|
|
132
133
|
const { libraryName, libraryVersion, highestSeverity } =
|
|
133
134
|
reportModel.compositeKey
|
|
135
|
+
|
|
134
136
|
const numOfCVEs = reportModel.cveArray.length
|
|
135
137
|
|
|
136
138
|
const table = getReportTable()
|
|
@@ -236,9 +238,11 @@ function buildHeader(
|
|
|
236
238
|
}
|
|
237
239
|
|
|
238
240
|
function buildBody(cveArray, advice) {
|
|
239
|
-
|
|
241
|
+
const orderedCvesWithSeverityAssigned = orderByHighestPriority(
|
|
242
|
+
cveArray.map(cve => findCVESeverity(cve))
|
|
243
|
+
)
|
|
240
244
|
|
|
241
|
-
const issueMessage = getIssueRow(
|
|
245
|
+
const issueMessage = getIssueRow(orderedCvesWithSeverityAssigned)
|
|
242
246
|
|
|
243
247
|
//todo different advice based on remediationGuidance being available or now
|
|
244
248
|
// console.log(advice)
|
|
@@ -254,7 +258,6 @@ function buildBody(cveArray, advice) {
|
|
|
254
258
|
}
|
|
255
259
|
|
|
256
260
|
function getIssueRow(cveArray) {
|
|
257
|
-
orderByHighestPriority(cveArray)
|
|
258
261
|
const cveMessagesList = getIssueCveMsgList(cveArray)
|
|
259
262
|
return [chalk.bold('Issue'), ':', `${cveMessagesList.join(', ')}`]
|
|
260
263
|
}
|
|
@@ -301,7 +304,6 @@ const getIssueCveMsgList = results => {
|
|
|
301
304
|
const cveMessages = []
|
|
302
305
|
|
|
303
306
|
results.forEach(reportSeverityModel => {
|
|
304
|
-
// @ts-ignore
|
|
305
307
|
const { colour, severity, name } = reportSeverityModel
|
|
306
308
|
|
|
307
309
|
const severityShorthand = chalk
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { ReportSeverityModel } from './reportSeverityModel'
|
|
2
2
|
import { ReportCVEModel } from './reportLibraryModel'
|
|
3
|
+
import {
|
|
4
|
+
ScaReportRemediationAdviceModel,
|
|
5
|
+
ScaReportVulnerabilityModel
|
|
6
|
+
} from '../../../scaAnalysis/common/models/ScaReportModel'
|
|
3
7
|
|
|
4
8
|
export class ReportList {
|
|
5
9
|
reportOutputList: ReportModelStructure[]
|
|
@@ -11,11 +15,17 @@ export class ReportList {
|
|
|
11
15
|
|
|
12
16
|
export class ReportModelStructure {
|
|
13
17
|
compositeKey: ReportCompositeKey
|
|
14
|
-
cveArray: ReportCVEModel[]
|
|
18
|
+
cveArray: ReportCVEModel[] | ScaReportVulnerabilityModel[]
|
|
19
|
+
remediationAdvice: ScaReportRemediationAdviceModel | null
|
|
15
20
|
|
|
16
|
-
constructor(
|
|
21
|
+
constructor(
|
|
22
|
+
compositeKey: ReportCompositeKey,
|
|
23
|
+
cveArray: ReportCVEModel[] | ScaReportVulnerabilityModel[],
|
|
24
|
+
remediationAdvice: ScaReportRemediationAdviceModel | null
|
|
25
|
+
) {
|
|
17
26
|
this.compositeKey = compositeKey
|
|
18
27
|
this.cveArray = cveArray
|
|
28
|
+
this.remediationAdvice = remediationAdvice
|
|
19
29
|
}
|
|
20
30
|
}
|
|
21
31
|
|
|
@@ -87,7 +87,7 @@ export async function vulnerabilityReportV2(config: any, reportId: string) {
|
|
|
87
87
|
const reportResponse = await getReport(config, reportId)
|
|
88
88
|
|
|
89
89
|
if (reportResponse !== undefined) {
|
|
90
|
-
|
|
90
|
+
const output = formatVulnerabilityOutput(
|
|
91
91
|
reportResponse.vulnerabilities,
|
|
92
92
|
config.applicationId,
|
|
93
93
|
config,
|