@contrast/contrast 1.0.10 → 1.0.11
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/README.md +1 -1
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +39 -28
- package/dist/audit/languageAnalysisEngine/report/models/reportGuidanceModel.js +6 -0
- package/dist/audit/languageAnalysisEngine/report/models/reportOutputModel.js +1 -2
- package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +1 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +11 -7
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +1 -2
- package/dist/commands/audit/auditConfig.js +3 -3
- package/dist/commands/audit/processAudit.js +4 -2
- package/dist/commands/auth/auth.js +1 -1
- package/dist/commands/config/config.js +2 -2
- package/dist/commands/scan/processScan.js +11 -4
- package/dist/commands/scan/sca/scaAnalysis.js +10 -3
- package/dist/common/HTTPClient.js +9 -0
- package/dist/common/fail.js +66 -0
- package/dist/common/versionChecker.js +1 -1
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +6 -3
- package/dist/constants.js +39 -1
- package/dist/index.js +5 -2
- package/dist/scaAnalysis/common/scaParserForGoAndJava.js +32 -0
- package/dist/scaAnalysis/common/treeUpload.js +20 -5
- package/dist/scaAnalysis/dotnet/analysis.js +15 -3
- package/dist/scaAnalysis/go/goAnalysis.js +8 -2
- package/dist/scaAnalysis/java/analysis.js +10 -6
- package/dist/scaAnalysis/java/index.js +7 -1
- package/dist/scaAnalysis/java/javaBuildDepsParser.js +19 -3
- package/dist/scaAnalysis/python/analysis.js +43 -5
- package/dist/scaAnalysis/python/index.js +7 -2
- package/dist/scaAnalysis/ruby/analysis.js +14 -4
- package/dist/scan/formatScanOutput.js +6 -5
- package/dist/scan/populateProjectIdAndProjectName.js +5 -0
- package/dist/scan/scan.js +4 -0
- package/dist/scan/scanConfig.js +3 -3
- package/dist/scan/scanResults.js +39 -3
- package/dist/telemetry/telemetry.js +137 -0
- package/dist/utils/getConfig.js +2 -2
- package/dist/utils/parsedCLIOptions.js +3 -1
- package/dist/utils/requestUtils.js +7 -1
- package/package.json +1 -1
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +57 -39
- package/src/audit/languageAnalysisEngine/report/models/reportGuidanceModel.ts +5 -0
- package/src/audit/languageAnalysisEngine/report/models/reportOutputModel.ts +1 -7
- package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +2 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +15 -8
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +2 -2
- package/src/commands/audit/auditConfig.ts +10 -3
- package/src/commands/audit/processAudit.ts +16 -2
- package/src/commands/auth/auth.js +3 -1
- package/src/commands/config/config.js +4 -2
- package/src/commands/scan/processScan.js +18 -4
- package/src/commands/scan/sca/scaAnalysis.js +11 -3
- package/src/common/HTTPClient.js +14 -0
- package/src/common/fail.js +75 -0
- package/src/common/versionChecker.ts +1 -1
- package/src/constants/constants.js +1 -1
- package/src/constants/locales.js +8 -4
- package/src/constants.js +43 -1
- package/src/index.ts +17 -2
- package/src/scaAnalysis/common/scaParserForGoAndJava.js +41 -0
- package/src/scaAnalysis/common/treeUpload.js +21 -6
- package/src/scaAnalysis/dotnet/analysis.js +21 -3
- package/src/scaAnalysis/go/goAnalysis.js +9 -2
- package/src/scaAnalysis/java/analysis.js +11 -6
- package/src/scaAnalysis/java/index.js +9 -1
- package/src/scaAnalysis/java/javaBuildDepsParser.js +25 -6
- package/src/scaAnalysis/python/analysis.js +49 -5
- package/src/scaAnalysis/python/index.js +7 -2
- package/src/scaAnalysis/ruby/analysis.js +16 -4
- package/src/scan/formatScanOutput.ts +7 -5
- package/src/scan/populateProjectIdAndProjectName.js +5 -1
- package/src/scan/scan.ts +4 -0
- package/src/scan/scanConfig.js +5 -3
- package/src/scan/scanResults.js +46 -3
- package/src/telemetry/telemetry.ts +154 -0
- package/src/utils/getConfig.ts +4 -6
- package/src/utils/parsedCLIOptions.js +14 -1
- package/src/utils/requestUtils.js +8 -1
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ const severityCountModel_1 = require("./models/severityCountModel");
|
|
|
13
13
|
const reportOutputModel_1 = require("./models/reportOutputModel");
|
|
14
14
|
const constants_1 = require("../../../constants/constants");
|
|
15
15
|
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
16
|
+
const reportGuidanceModel_1 = require("./models/reportGuidanceModel");
|
|
16
17
|
const createSummaryMessage = (numberOfVulnerableLibraries, numberOfCves) => {
|
|
17
18
|
numberOfVulnerableLibraries === 1
|
|
18
19
|
? console.log(`Found 1 vulnerable library containing ${numberOfCves} CVE`)
|
|
@@ -92,10 +93,10 @@ const printFormattedOutput = (config, libraries, numberOfVulnerableLibraries, nu
|
|
|
92
93
|
colWidths: [12, 1, 100]
|
|
93
94
|
});
|
|
94
95
|
const header = buildHeader(highestSeverity, contrastHeaderNumCounter, libraryName, libraryVersion, numOfCVEs);
|
|
95
|
-
const advice = gatherRemediationAdvice(guidance,
|
|
96
|
+
const advice = gatherRemediationAdvice(guidance, libraryName, libraryVersion);
|
|
96
97
|
const body = buildBody(reportModel.cveArray, advice);
|
|
97
98
|
const reportOutputModel = new reportOutputModel_1.ReportOutputModel(header, body);
|
|
98
|
-
table.push(reportOutputModel.body.issueMessage, reportOutputModel.body.
|
|
99
|
+
table.push(reportOutputModel.body.issueMessage, reportOutputModel.body.adviceMessage);
|
|
99
100
|
console.log(reportOutputModel.header.vulnMessage, reportOutputModel.header.introducesMessage);
|
|
100
101
|
console.log(table.toString() + '\n');
|
|
101
102
|
}
|
|
@@ -107,9 +108,10 @@ exports.printFormattedOutput = printFormattedOutput;
|
|
|
107
108
|
function buildHeader(highestSeverity, contrastHeaderNum, libraryName, version, numOfCVEs) {
|
|
108
109
|
const vulnerabilityPluralised = numOfCVEs > 1 ? 'vulnerabilities' : 'vulnerability';
|
|
109
110
|
const formattedHeaderNum = buildFormattedHeaderNum(contrastHeaderNum);
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
const headerColour = chalk_1.default.hex(highestSeverity.outputColour);
|
|
112
|
+
const headerNumAndSeverity = headerColour(`${formattedHeaderNum} - [${highestSeverity.severity}]`);
|
|
113
|
+
const libraryNameAndVersion = headerColour.bold(`${libraryName}-${version}`);
|
|
114
|
+
const vulnMessage = `${headerNumAndSeverity} ${libraryNameAndVersion}`;
|
|
113
115
|
const introducesMessage = `introduces ${numOfCVEs} ${vulnerabilityPluralised}`;
|
|
114
116
|
return new reportOutputModel_1.ReportOutputHeaderModel(vulnMessage, introducesMessage);
|
|
115
117
|
}
|
|
@@ -125,29 +127,27 @@ function buildBody(cveArray, advice) {
|
|
|
125
127
|
cveMessages.push(builtMessage);
|
|
126
128
|
});
|
|
127
129
|
const numAndSeverityType = getNumOfAndSeverityType(cveArray);
|
|
128
|
-
const issueMessage = [
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
const issueMessage = [
|
|
131
|
+
chalk_1.default.bold('Issue'),
|
|
132
|
+
':',
|
|
133
|
+
`${numAndSeverityType} ${cveMessages.join(', ')}`
|
|
134
|
+
];
|
|
135
|
+
const minOrMax = advice.maximum ? advice.maximum : advice.minimum;
|
|
136
|
+
const displayAdvice = minOrMax
|
|
137
|
+
? `Change to version ${chalk_1.default.bold(minOrMax)}`
|
|
138
|
+
: 'No recommendation is available according to our data. Upgrade to the latest stable is the best advice we can give.';
|
|
133
139
|
const adviceMessage = [chalk_1.default.bold('Advice'), ':', displayAdvice];
|
|
134
|
-
return new reportOutputModel_1.ReportOutputBodyModel(issueMessage,
|
|
140
|
+
return new reportOutputModel_1.ReportOutputBodyModel(issueMessage, adviceMessage);
|
|
135
141
|
}
|
|
136
142
|
exports.buildBody = buildBody;
|
|
137
|
-
function gatherRemediationAdvice(guidance,
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
maximum: undefined,
|
|
141
|
-
latest: undefined
|
|
142
|
-
};
|
|
143
|
-
const data = guidance[reportModel.compositeKey.libraryName +
|
|
144
|
-
'@' +
|
|
145
|
-
reportModel.compositeKey.libraryVersion];
|
|
143
|
+
function gatherRemediationAdvice(guidance, libraryName, libraryVersion) {
|
|
144
|
+
const guidanceModel = new reportGuidanceModel_1.ReportGuidanceModel();
|
|
145
|
+
const data = guidance[libraryName + '@' + libraryVersion];
|
|
146
146
|
if (data) {
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
guidanceModel.minimum = data.minUpgradeVersion;
|
|
148
|
+
guidanceModel.maximum = data.maxUpgradeVersion;
|
|
149
149
|
}
|
|
150
|
-
return
|
|
150
|
+
return guidanceModel;
|
|
151
151
|
}
|
|
152
152
|
exports.gatherRemediationAdvice = gatherRemediationAdvice;
|
|
153
153
|
function buildFormattedHeaderNum(contrastHeaderNum) {
|
|
@@ -156,11 +156,22 @@ function buildFormattedHeaderNum(contrastHeaderNum) {
|
|
|
156
156
|
exports.buildFormattedHeaderNum = buildFormattedHeaderNum;
|
|
157
157
|
function getNumOfAndSeverityType(cveArray) {
|
|
158
158
|
const { critical, high, medium, low, note } = (0, reportUtils_1.severityCountAllCVEs)(cveArray, new severityCountModel_1.SeverityCountModel());
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
const
|
|
162
|
-
const
|
|
163
|
-
const
|
|
159
|
+
const criticalNumCheck = critical > 0;
|
|
160
|
+
const highNumCheck = high > 0;
|
|
161
|
+
const highDivider = highNumCheck ? '|' : '';
|
|
162
|
+
const mediumNumCheck = medium > 0;
|
|
163
|
+
const mediumDivider = mediumNumCheck ? '|' : '';
|
|
164
|
+
const lowNumCheck = low > 0;
|
|
165
|
+
const lowDivider = lowNumCheck ? '|' : '';
|
|
166
|
+
const noteNumCheck = low > 0;
|
|
167
|
+
const noteDivider = noteNumCheck ? '|' : '';
|
|
168
|
+
const criticalMessage = criticalNumCheck
|
|
169
|
+
? `${critical} Critical ${highDivider}`
|
|
170
|
+
: '';
|
|
171
|
+
const highMessage = highNumCheck ? `${high} High ${mediumDivider}` : '';
|
|
172
|
+
const mediumMessage = mediumNumCheck ? `${medium} Medium ${lowDivider}` : '';
|
|
173
|
+
const lowMessage = lowNumCheck ? `${low} Low ${noteDivider}` : '';
|
|
174
|
+
const noteMessage = noteNumCheck ? `${note} Note` : '';
|
|
164
175
|
return `${criticalMessage} ${highMessage} ${mediumMessage} ${lowMessage} ${noteMessage}`
|
|
165
176
|
.replace(/\s+/g, ' ')
|
|
166
177
|
.trim();
|
|
@@ -16,9 +16,8 @@ class ReportOutputHeaderModel {
|
|
|
16
16
|
}
|
|
17
17
|
exports.ReportOutputHeaderModel = ReportOutputHeaderModel;
|
|
18
18
|
class ReportOutputBodyModel {
|
|
19
|
-
constructor(issueMessage,
|
|
19
|
+
constructor(issueMessage, adviceMessage) {
|
|
20
20
|
this.issueMessage = issueMessage;
|
|
21
|
-
this.issueMessageCves = issueMessageCves;
|
|
22
21
|
this.adviceMessage = adviceMessage;
|
|
23
22
|
}
|
|
24
23
|
}
|
|
@@ -32,6 +32,8 @@ const reportUtils_1 = require("./utils/reportUtils");
|
|
|
32
32
|
const i18n_1 = __importDefault(require("i18n"));
|
|
33
33
|
const chalk_1 = __importDefault(require("chalk"));
|
|
34
34
|
const constants = __importStar(require("../../../constants/constants"));
|
|
35
|
+
const severityCountModel_1 = require("./models/severityCountModel");
|
|
36
|
+
const common = __importStar(require("../../../common/fail"));
|
|
35
37
|
function convertKeysToStandardFormat(config, guidance) {
|
|
36
38
|
let convertedGuidance = guidance;
|
|
37
39
|
switch (config.language) {
|
|
@@ -70,16 +72,16 @@ function formatVulnerabilityOutput(libraryVulnerabilityResponse, id, config, rem
|
|
|
70
72
|
console.log(i18n_1.default.__('scanNoVulnerabilitiesFoundGoodWork'));
|
|
71
73
|
console.log(chalk_1.default.bold(`Found ${numberOfVulnerableLibraries} vulnerabilities`));
|
|
72
74
|
console.log(i18n_1.default.__('foundDetailedVulnerabilities', String(0), String(0), String(0), String(0), String(0)));
|
|
75
|
+
return [false, 0, [new severityCountModel_1.SeverityCountModel()]];
|
|
73
76
|
}
|
|
74
77
|
else {
|
|
75
78
|
let numberOfCves = 0;
|
|
76
79
|
vulnerableLibraries.forEach(lib => (numberOfCves += lib.cveArray.length));
|
|
77
80
|
const hasSomeVulnerabilitiesReported = (0, commonReportingFunctions_1.printVulnerabilityResponse)(config, vulnerableLibraries, numberOfVulnerableLibraries, numberOfCves, guidance);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
];
|
|
81
|
+
let severityCount = new severityCountModel_1.SeverityCountModel();
|
|
82
|
+
severityCount = (0, reportUtils_1.severityCountAllLibraries)(vulnerableLibraries, severityCount);
|
|
83
|
+
severityCount.total = severityCount.getTotal;
|
|
84
|
+
return [hasSomeVulnerabilitiesReported, numberOfCves, severityCount];
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
87
|
exports.formatVulnerabilityOutput = formatVulnerabilityOutput;
|
|
@@ -87,10 +89,12 @@ async function vulnerabilityReportV2(config, reportId) {
|
|
|
87
89
|
console.log();
|
|
88
90
|
const reportResponse = await (0, commonReportingFunctions_1.getReport)(config, reportId);
|
|
89
91
|
if (reportResponse !== undefined) {
|
|
90
|
-
|
|
91
|
-
formatVulnerabilityOutput(reportResponse.vulnerabilities, config.applicationId, config, reportResponse.remediationGuidance
|
|
92
|
+
let output = formatVulnerabilityOutput(reportResponse.vulnerabilities, config.applicationId, config, reportResponse.remediationGuidance
|
|
92
93
|
? reportResponse.remediationGuidance
|
|
93
94
|
: {});
|
|
95
|
+
if (config.fail) {
|
|
96
|
+
common.processFail(config, output[2]);
|
|
97
|
+
}
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
100
|
exports.vulnerabilityReportV2 = vulnerabilityReportV2;
|
|
@@ -46,8 +46,7 @@ function convertGenericToTypedLibraryVulns(libraries) {
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
exports.convertGenericToTypedLibraryVulns = convertGenericToTypedLibraryVulns;
|
|
49
|
-
function severityCountAllLibraries(vulnerableLibraries) {
|
|
50
|
-
const severityCount = new severityCountModel_1.SeverityCountModel();
|
|
49
|
+
function severityCountAllLibraries(vulnerableLibraries, severityCount) {
|
|
51
50
|
vulnerableLibraries.forEach(lib => severityCountAllCVEs(lib.cveArray, severityCount));
|
|
52
51
|
return severityCount;
|
|
53
52
|
}
|
|
@@ -6,9 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.getAuditConfig = void 0;
|
|
7
7
|
const paramHandler_1 = __importDefault(require("../../utils/paramsUtil/paramHandler"));
|
|
8
8
|
const constants_1 = __importDefault(require("../../constants"));
|
|
9
|
-
const parsedCLIOptions_1 =
|
|
10
|
-
const getAuditConfig = (argv) => {
|
|
11
|
-
const auditParameters = parsedCLIOptions_1.
|
|
9
|
+
const parsedCLIOptions_1 = require("../../utils/parsedCLIOptions");
|
|
10
|
+
const getAuditConfig = async (contrastConf, command, argv) => {
|
|
11
|
+
const auditParameters = await (0, parsedCLIOptions_1.getCommandLineArgsCustom)(contrastConf, command, argv, constants_1.default.commandLineDefinitions.auditOptionDefinitions);
|
|
12
12
|
const paramsAuth = paramHandler_1.default.getAuth(auditParameters);
|
|
13
13
|
return { ...paramsAuth, ...auditParameters };
|
|
14
14
|
};
|
|
@@ -4,13 +4,15 @@ exports.processAudit = void 0;
|
|
|
4
4
|
const auditConfig_1 = require("./auditConfig");
|
|
5
5
|
const help_1 = require("./help");
|
|
6
6
|
const scaAnalysis_1 = require("../scan/sca/scaAnalysis");
|
|
7
|
-
const
|
|
7
|
+
const telemetry_1 = require("../../telemetry/telemetry");
|
|
8
|
+
const processAudit = async (contrastConf, argv) => {
|
|
8
9
|
if (argv.indexOf('--help') != -1) {
|
|
9
10
|
printHelpMessage();
|
|
10
11
|
process.exit(0);
|
|
11
12
|
}
|
|
12
|
-
const config = (0, auditConfig_1.getAuditConfig)(argv);
|
|
13
|
+
const config = await (0, auditConfig_1.getAuditConfig)(contrastConf, 'audit', argv);
|
|
13
14
|
await (0, scaAnalysis_1.processSca)(config);
|
|
15
|
+
await (0, telemetry_1.sendTelemetryConfigAsObject)(config, 'audit', argv, 'SUCCESS', config.language);
|
|
14
16
|
};
|
|
15
17
|
exports.processAudit = processAudit;
|
|
16
18
|
const printHelpMessage = () => {
|
|
@@ -11,7 +11,7 @@ const parsedCLIOptions = require('../../utils/parsedCLIOptions');
|
|
|
11
11
|
const constants = require('../../constants');
|
|
12
12
|
const commandLineUsage = require('command-line-usage');
|
|
13
13
|
const processAuth = async (argv, config) => {
|
|
14
|
-
let authParams = parsedCLIOptions.getCommandLineArgsCustom(argv, constants.commandLineDefinitions.authOptionDefinitions);
|
|
14
|
+
let authParams = await parsedCLIOptions.getCommandLineArgsCustom(config, 'auth', argv, constants.commandLineDefinitions.authOptionDefinitions);
|
|
15
15
|
if (authParams.help) {
|
|
16
16
|
console.log(authUsageGuide);
|
|
17
17
|
process.exit(0);
|
|
@@ -3,9 +3,9 @@ const parsedCLIOptions = require('../../utils/parsedCLIOptions');
|
|
|
3
3
|
const constants = require('../../constants');
|
|
4
4
|
const commandLineUsage = require('command-line-usage');
|
|
5
5
|
const i18n = require('i18n');
|
|
6
|
-
const processConfig = (argv, config) => {
|
|
6
|
+
const processConfig = async (argv, config) => {
|
|
7
7
|
try {
|
|
8
|
-
let configParams = parsedCLIOptions.getCommandLineArgsCustom(argv, constants.commandLineDefinitions.configOptionDefinitions);
|
|
8
|
+
let configParams = await parsedCLIOptions.getCommandLineArgsCustom(config, 'config', argv, constants.commandLineDefinitions.configOptionDefinitions);
|
|
9
9
|
if (configParams.help) {
|
|
10
10
|
console.log(configUsageGuide);
|
|
11
11
|
process.exit(0);
|
|
@@ -5,18 +5,25 @@ const { saveScanFile } = require('../../utils/saveFile');
|
|
|
5
5
|
const { ScanResultsModel } = require('../../scan/models/scanResultsModel');
|
|
6
6
|
const { formatScanOutput } = require('../../scan/formatScanOutput');
|
|
7
7
|
const { processSca } = require('./sca/scaAnalysis');
|
|
8
|
-
const
|
|
9
|
-
|
|
8
|
+
const common = require('../../common/fail');
|
|
9
|
+
const { sendTelemetryConfigAsObject } = require('../../telemetry/telemetry');
|
|
10
|
+
const processScan = async (contrastConf, argv) => {
|
|
11
|
+
let config = await scanConfig.getScanConfig(contrastConf, 'scan', argv);
|
|
12
|
+
let output = undefined;
|
|
10
13
|
if (config.experimental) {
|
|
11
|
-
await processSca(config);
|
|
14
|
+
await processSca(config, argv);
|
|
12
15
|
}
|
|
13
16
|
let scanResults = new ScanResultsModel(await startScan(config));
|
|
17
|
+
await sendTelemetryConfigAsObject(config, 'scan', argv, 'SUCCESS', scanResults.scanDetail.language);
|
|
14
18
|
if (scanResults.scanResultsInstances !== undefined) {
|
|
15
|
-
formatScanOutput(scanResults);
|
|
19
|
+
output = formatScanOutput(scanResults);
|
|
16
20
|
}
|
|
17
21
|
if (config.save !== undefined) {
|
|
18
22
|
await saveScanFile(config, scanResults);
|
|
19
23
|
}
|
|
24
|
+
if (config.fail) {
|
|
25
|
+
common.processFail(config, output);
|
|
26
|
+
}
|
|
20
27
|
};
|
|
21
28
|
module.exports = {
|
|
22
29
|
processScan
|
|
@@ -15,20 +15,25 @@ const i18n = require('i18n');
|
|
|
15
15
|
const { vulnerabilityReportV2 } = require('../../../audit/languageAnalysisEngine/report/reportingFeature');
|
|
16
16
|
const auditSave = require('../../../audit/save');
|
|
17
17
|
const { dotNetAnalysis } = require('../../../scaAnalysis/dotnet');
|
|
18
|
+
const { auditUsageGuide } = require('../../audit/help');
|
|
18
19
|
const rootFile = require('../../../audit/languageAnalysisEngine/getProjectRootFilenames');
|
|
19
20
|
const path = require('path');
|
|
20
21
|
const processSca = async (config) => {
|
|
21
22
|
const startTime = performance.now();
|
|
22
23
|
let filesFound;
|
|
24
|
+
if (config.help) {
|
|
25
|
+
console.log(auditUsageGuide);
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
23
28
|
const projectStats = await rootFile.getProjectStats(config.file);
|
|
24
29
|
let pathWithFile = projectStats.isFile();
|
|
25
|
-
|
|
30
|
+
config.fileName = config.file;
|
|
26
31
|
config.file = pathWithFile
|
|
27
32
|
? rootFile.getDirectoryFromPathGiven(config.file).concat('/')
|
|
28
33
|
: config.file;
|
|
29
34
|
filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config.file);
|
|
30
35
|
if (filesFound.length > 1 && pathWithFile) {
|
|
31
|
-
filesFound = filesFound.filter(i => Object.values(i)[0].includes(path.basename(fileName)));
|
|
36
|
+
filesFound = filesFound.filter(i => Object.values(i)[0].includes(path.basename(config.fileName)));
|
|
32
37
|
}
|
|
33
38
|
let messageToSend = undefined;
|
|
34
39
|
if (filesFound.length === 1) {
|
|
@@ -89,7 +94,9 @@ const processSca = async (config) => {
|
|
|
89
94
|
throw new Error();
|
|
90
95
|
}
|
|
91
96
|
else {
|
|
92
|
-
throw new Error(
|
|
97
|
+
throw new Error(`multiple language files detected \n` +
|
|
98
|
+
JSON.stringify(filesFound) +
|
|
99
|
+
`\nplease use --file to audit one language only. Example: contrast audit --file package-lock.json`);
|
|
93
100
|
}
|
|
94
101
|
}
|
|
95
102
|
};
|
|
@@ -253,6 +253,12 @@ HTTPClient.prototype.getLatestVersion = function getLatestVersion() {
|
|
|
253
253
|
'https://pkg.contrastsecurity.com/artifactory/cli/latest-version.txt';
|
|
254
254
|
return requestUtils.sendRequest({ method: 'get', options });
|
|
255
255
|
};
|
|
256
|
+
HTTPClient.prototype.postTelemetry = function postTelemetry(config, requestBody) {
|
|
257
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
258
|
+
options.url = createTelemetryEventUrl(config);
|
|
259
|
+
options.body = requestBody;
|
|
260
|
+
return requestUtils.sendRequest({ method: 'post', options });
|
|
261
|
+
};
|
|
256
262
|
HTTPClient.prototype.postAnalyticsFunction = function (config, provider, body) {
|
|
257
263
|
const url = createAnalyticsFunctionPostUrl(config, provider);
|
|
258
264
|
const options = { ...this.requestOptions, body, url };
|
|
@@ -319,6 +325,9 @@ function createDataUrl() {
|
|
|
319
325
|
function createSbomUrl(config, type) {
|
|
320
326
|
return `${config.host}/Contrast/api/ng/${config.organizationId}/applications/${config.applicationId}/libraries/sbom/${type}`;
|
|
321
327
|
}
|
|
328
|
+
function createTelemetryEventUrl(config) {
|
|
329
|
+
return `${config.host}/Contrast/api/sast/organizations/${config.organizationId}/cli`;
|
|
330
|
+
}
|
|
322
331
|
module.exports = HTTPClient;
|
|
323
332
|
module.exports.pollForAuthUrl = pollForAuthUrl;
|
|
324
333
|
module.exports.getServerlessHost = getServerlessHost;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const i18n = require('i18n');
|
|
3
|
+
const processFail = (config, reportResults) => {
|
|
4
|
+
if (config.severity !== undefined) {
|
|
5
|
+
if (reportResults[config.severity] !== undefined &&
|
|
6
|
+
isSeverityViolation(config.severity, reportResults)) {
|
|
7
|
+
failPipeline('failSeverityOptionErrorMessage');
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
if (config.severity === undefined && reportResults.total > 0) {
|
|
11
|
+
failPipeline('failThresholdOptionErrorMessage');
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const isSeverityViolation = (severity, reportResults) => {
|
|
15
|
+
let count = 0;
|
|
16
|
+
switch (severity) {
|
|
17
|
+
case 'critical':
|
|
18
|
+
count += reportResults.critical;
|
|
19
|
+
break;
|
|
20
|
+
case 'high':
|
|
21
|
+
count += reportResults.high + reportResults.critical;
|
|
22
|
+
break;
|
|
23
|
+
case 'medium':
|
|
24
|
+
count += reportResults.medium + reportResults.low + reportResults.critical;
|
|
25
|
+
break;
|
|
26
|
+
case 'low':
|
|
27
|
+
count +=
|
|
28
|
+
reportResults.high + reportResults.critical + reportResults.medium;
|
|
29
|
+
break;
|
|
30
|
+
case 'note':
|
|
31
|
+
if (reportResults.note == reportResults.total) {
|
|
32
|
+
count = 0;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
count = reportResults.total;
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
38
|
+
default:
|
|
39
|
+
count = 0;
|
|
40
|
+
}
|
|
41
|
+
return count > 0;
|
|
42
|
+
};
|
|
43
|
+
const failPipeline = (message = '') => {
|
|
44
|
+
console.log('\n ******************************** ' +
|
|
45
|
+
i18n.__('snapshotFailureHeader') +
|
|
46
|
+
' *********************************\n' +
|
|
47
|
+
i18n.__(message));
|
|
48
|
+
process.exit(1);
|
|
49
|
+
};
|
|
50
|
+
const parseSeverity = severity => {
|
|
51
|
+
const severities = ['NOTE', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL'];
|
|
52
|
+
if (severities.includes(severity.toUpperCase())) {
|
|
53
|
+
return severity.toLowerCase();
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
console.log(severity +
|
|
57
|
+
' Not recognised as a severity type please use LOW, MEDIUM, HIGH, CRITICAL, NOTE');
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
module.exports = {
|
|
62
|
+
failPipeline,
|
|
63
|
+
processFail,
|
|
64
|
+
isSeverityViolation,
|
|
65
|
+
parseSeverity
|
|
66
|
+
};
|
|
@@ -23,7 +23,7 @@ const getLatestVersion = async (config) => {
|
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
25
|
async function findLatestCLIVersion(config) {
|
|
26
|
-
const messageHidden = config.get('
|
|
26
|
+
const messageHidden = config.get('isCI');
|
|
27
27
|
if (!messageHidden) {
|
|
28
28
|
let latestCLIVersion = await getLatestVersion(config);
|
|
29
29
|
latestCLIVersion = latestCLIVersion.substring(8);
|
|
@@ -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.11';
|
|
16
16
|
const TIMEOUT = 120000;
|
|
17
17
|
const HIGH_COLOUR = '#ff9900';
|
|
18
18
|
const CRITICAL_COLOUR = '#e35858';
|
|
@@ -79,8 +79,9 @@ const en_locales = () => {
|
|
|
79
79
|
constantsHostId: 'Provide the name of the host and optionally the port expressed as "<host>:<port>".',
|
|
80
80
|
constantsApplicationName: 'The name of the application cataloged by Contrast UI',
|
|
81
81
|
constantsCatalogueApplication: 'Provide this if you want to catalogue an application',
|
|
82
|
+
failOptionErrorMessage: ' FAIL - CVEs have been detected that match at least the cve_severity option specified.',
|
|
82
83
|
constantsLanguage: 'Valid values are JAVA, DOTNET, NODE, PYTHON and RUBY. If there are multiple project configuration files in the project_path, language is also required. Also, provide this when cataloguing an application',
|
|
83
|
-
constantsFilePath: `
|
|
84
|
+
constantsFilePath: `Specify a directory or the file where dependencies are declared. (By default, CodeSec will search for project files in the current directory.)`,
|
|
84
85
|
constantsSilent: 'Silences JSON output.',
|
|
85
86
|
constantsAppGroups: 'Assign your application to one or more pre-existing groups when using the catalogue command. Group lists should be comma separated.',
|
|
86
87
|
constantsVersion: 'Displays CLI Version you are currently on.',
|
|
@@ -93,7 +94,8 @@ const en_locales = () => {
|
|
|
93
94
|
constantsProjectId: 'The ID associated with a scan project. Replace <ProjectID> with the ID for the scan project. To find the ID, select a scan project in Contrast and locate the last number in the URL.',
|
|
94
95
|
constantsReport: 'Display vulnerability information for this application',
|
|
95
96
|
constantsFail: 'Set the process to fail if this option is set in combination with --cve_severity.',
|
|
96
|
-
|
|
97
|
+
failThresholdOptionErrorMessage: 'More than 0 vulnerabilities found',
|
|
98
|
+
failSeverityOptionErrorMessage: ' FAIL - Results detected vulnerabilities over accepted severity level',
|
|
97
99
|
constantsSeverity: 'Allows the user to report libraries with vulnerabilities above a chosen severity level. For example, cve_severity medium only reports libraries with vulnerabilities at medium or higher severity. Values for level are high, medium or low.',
|
|
98
100
|
constantsCount: 'The number of CVEs that must be exceeded to fail a build',
|
|
99
101
|
constantsHeader: 'CodeSec by Contrast Security',
|
|
@@ -276,7 +278,8 @@ const en_locales = () => {
|
|
|
276
278
|
constantsAuditPrerequisitesContentPHPMessage: `${chalk.bold('PHP:')} composer.json and composer.lock\n`,
|
|
277
279
|
constantsAuditOptions: 'Audit Options',
|
|
278
280
|
auditOptionsSaveDescription: 'Generate and save an SBOM (Software Bill of Materials)\n',
|
|
279
|
-
auditOptionsSaveOptionsDescription: 'Valid options are: spdx
|
|
281
|
+
auditOptionsSaveOptionsDescription: 'Valid options are: --save spdx and --save cyclonedx (CycloneDX is the default format.)',
|
|
282
|
+
exceededFreeTier: `It looks like you are really loving CodeSec! \nYou have reached the monthly scan limit on the FREE tier. \nPlease contact sales@contrastsecurity.com to upgrade.`,
|
|
280
283
|
scanNotCompleted: 'Scan not completed. Check for framework and language support here: %s',
|
|
281
284
|
auditNotCompleted: 'audit not completed. Please try again',
|
|
282
285
|
scanNoVulnerabilitiesFound: '🎉 No vulnerabilities found.',
|
package/dist/constants.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const commandLineUsage = require('command-line-usage');
|
|
3
3
|
const i18n = require('i18n');
|
|
4
4
|
const { en_locales } = require('./constants/locales.js');
|
|
5
|
+
const { parseSeverity } = require('./common/fail');
|
|
5
6
|
i18n.configure({
|
|
6
7
|
staticCatalog: {
|
|
7
8
|
en: en_locales()
|
|
@@ -93,6 +94,22 @@ const scanOptionDefinitions = [
|
|
|
93
94
|
'}: ' +
|
|
94
95
|
i18n.__('constantsProxyServer')
|
|
95
96
|
},
|
|
97
|
+
{
|
|
98
|
+
name: 'fail',
|
|
99
|
+
type: Boolean,
|
|
100
|
+
description: '{bold ' +
|
|
101
|
+
i18n.__('constantsOptional') +
|
|
102
|
+
'}: ' +
|
|
103
|
+
i18n.__('failOptionErrorMessage')
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'severity',
|
|
107
|
+
type: severity => parseSeverity(severity),
|
|
108
|
+
description: '{bold ' +
|
|
109
|
+
i18n.__('constantsOptional') +
|
|
110
|
+
'}: ' +
|
|
111
|
+
i18n.__('constantsSeverity')
|
|
112
|
+
},
|
|
96
113
|
{
|
|
97
114
|
name: 'ff',
|
|
98
115
|
type: Boolean,
|
|
@@ -195,6 +212,22 @@ const auditOptionDefinitions = [
|
|
|
195
212
|
'}: ' +
|
|
196
213
|
i18n.__('constantsFilePath')
|
|
197
214
|
},
|
|
215
|
+
{
|
|
216
|
+
name: 'fail',
|
|
217
|
+
type: Boolean,
|
|
218
|
+
description: '{bold ' +
|
|
219
|
+
i18n.__('constantsOptional') +
|
|
220
|
+
'}: ' +
|
|
221
|
+
i18n.__('failOptionErrorMessage')
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: 'severity',
|
|
225
|
+
type: severity => parseSeverity(severity),
|
|
226
|
+
description: '{bold ' +
|
|
227
|
+
i18n.__('constantsOptional') +
|
|
228
|
+
'}: ' +
|
|
229
|
+
i18n.__('constantsSeverity')
|
|
230
|
+
},
|
|
198
231
|
{
|
|
199
232
|
name: 'app-groups',
|
|
200
233
|
description: '{bold ' +
|
|
@@ -227,6 +260,7 @@ const auditOptionDefinitions = [
|
|
|
227
260
|
{
|
|
228
261
|
name: 'ignore-dev',
|
|
229
262
|
type: Boolean,
|
|
263
|
+
alias: 'i',
|
|
230
264
|
description: '{bold ' +
|
|
231
265
|
i18n.__('constantsOptional') +
|
|
232
266
|
'}: ' +
|
|
@@ -259,7 +293,6 @@ const auditOptionDefinitions = [
|
|
|
259
293
|
},
|
|
260
294
|
{
|
|
261
295
|
name: 'host',
|
|
262
|
-
alias: 'h',
|
|
263
296
|
description: '{bold ' +
|
|
264
297
|
i18n.__('constantsRequired') +
|
|
265
298
|
'}: ' +
|
|
@@ -302,6 +335,11 @@ const auditOptionDefinitions = [
|
|
|
302
335
|
i18n.__('constantsOptional') +
|
|
303
336
|
'}: ' +
|
|
304
337
|
i18n.__('scanOptionsTimeoutSummary')
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
name: 'help',
|
|
341
|
+
alias: 'h',
|
|
342
|
+
type: Boolean
|
|
305
343
|
}
|
|
306
344
|
];
|
|
307
345
|
const mainUsageGuide = commandLineUsage([
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@ const lambda_1 = require("./lambda/lambda");
|
|
|
15
15
|
const getConfig_1 = require("./utils/getConfig");
|
|
16
16
|
const versionChecker_1 = require("./common/versionChecker");
|
|
17
17
|
const errorHandling_1 = require("./common/errorHandling");
|
|
18
|
+
const telemetry_1 = require("./telemetry/telemetry");
|
|
18
19
|
const { commandLineDefinitions: { mainUsageGuide, mainDefinition } } = constants_1.default;
|
|
19
20
|
const config = (0, getConfig_1.localConfig)(constants_2.APP_NAME, constants_2.APP_VERSION);
|
|
20
21
|
const getMainOption = () => {
|
|
@@ -58,10 +59,10 @@ const start = async () => {
|
|
|
58
59
|
return await (0, lambda_1.processLambda)(argvMain);
|
|
59
60
|
}
|
|
60
61
|
if (command === 'scan') {
|
|
61
|
-
return await (0, processScan_1.processScan)(argvMain);
|
|
62
|
+
return await (0, processScan_1.processScan)(config, argvMain);
|
|
62
63
|
}
|
|
63
64
|
if (command === 'audit') {
|
|
64
|
-
return await (0, processAudit_1.processAudit)(argvMain);
|
|
65
|
+
return await (0, processAudit_1.processAudit)(config, argvMain);
|
|
65
66
|
}
|
|
66
67
|
if (command === 'help' ||
|
|
67
68
|
argvMain.includes('--help') ||
|
|
@@ -73,9 +74,11 @@ const start = async () => {
|
|
|
73
74
|
foundCommand
|
|
74
75
|
? console.log(`Unknown Command: Did you mean "${foundCommand}"? \nUse "${foundCommand} --help" for the full list of options`)
|
|
75
76
|
: console.log(`Unknown Command: ${command} \nUse --help for the full list`);
|
|
77
|
+
await (0, telemetry_1.sendTelemetryConfigAsConfObj)(config, command, argvMain, 'FAILURE', 'undefined');
|
|
76
78
|
}
|
|
77
79
|
else {
|
|
78
80
|
console.log(`Unknown Command: ${command} \nUse --help for the full list`);
|
|
81
|
+
await (0, telemetry_1.sendTelemetryConfigAsConfObj)(config, command, argvMain, 'FAILURE', 'undefined');
|
|
79
82
|
}
|
|
80
83
|
process.exit(9);
|
|
81
84
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const parseDependenciesForSCAServices = dependencyTreeObject => {
|
|
3
|
+
let parsedDependencyTree = {};
|
|
4
|
+
let subDeps;
|
|
5
|
+
for (let tree in dependencyTreeObject) {
|
|
6
|
+
let unParsedDependencyTree = dependencyTreeObject[tree];
|
|
7
|
+
for (let dependency in unParsedDependencyTree) {
|
|
8
|
+
subDeps = parseSubDependencies(unParsedDependencyTree[dependency].edges);
|
|
9
|
+
let parsedDependency = {
|
|
10
|
+
name: unParsedDependencyTree[dependency].artifactID,
|
|
11
|
+
group: unParsedDependencyTree[dependency].group,
|
|
12
|
+
version: unParsedDependencyTree[dependency].version,
|
|
13
|
+
directDependency: unParsedDependencyTree[dependency].type === 'direct',
|
|
14
|
+
isProduction: true,
|
|
15
|
+
dependencies: subDeps
|
|
16
|
+
};
|
|
17
|
+
parsedDependencyTree[dependency] = parsedDependency;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return parsedDependencyTree;
|
|
21
|
+
};
|
|
22
|
+
const parseSubDependencies = dependencies => {
|
|
23
|
+
let subDeps = [];
|
|
24
|
+
for (let x in dependencies) {
|
|
25
|
+
subDeps.push(dependencies[x]);
|
|
26
|
+
}
|
|
27
|
+
return subDeps;
|
|
28
|
+
};
|
|
29
|
+
module.exports = {
|
|
30
|
+
parseDependenciesForSCAServices,
|
|
31
|
+
parseSubDependencies
|
|
32
|
+
};
|