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