@contrast/contrast 1.0.4 → 1.0.7
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/.prettierignore +0 -3
- package/dist/audit/autodetection/autoDetectLanguage.js +32 -0
- package/dist/audit/catalogueApplication/catalogueApplication.js +2 -11
- package/dist/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +4 -2
- package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
- package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
- package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
- package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +6 -2
- package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +39 -1
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +69 -30
- package/dist/audit/languageAnalysisEngine/report/models/reportOutputModel.js +24 -0
- package/dist/audit/languageAnalysisEngine/report/models/reportSeverityModel.js +3 -1
- package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +13 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +2 -2
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +56 -45
- package/dist/audit/languageAnalysisEngine/sendSnapshot.js +65 -17
- package/dist/commands/audit/auditConfig.js +8 -2
- package/dist/commands/audit/auditController.js +9 -3
- package/dist/commands/audit/processAudit.js +1 -1
- package/dist/commands/scan/processScan.js +7 -4
- package/dist/commands/scan/sca/scaAnalysis.js +60 -0
- package/dist/common/HTTPClient.js +50 -16
- package/dist/common/errorHandling.js +11 -16
- package/dist/common/versionChecker.js +1 -1
- package/dist/constants/constants.js +24 -2
- package/dist/constants/locales.js +31 -36
- package/dist/constants.js +20 -0
- package/dist/lambda/analytics.js +11 -0
- package/dist/lambda/lambda.js +35 -4
- package/dist/lambda/types.js +13 -0
- package/dist/scaAnalysis/common/formatMessage.js +35 -0
- package/dist/scaAnalysis/common/treeUpload.js +29 -0
- package/dist/scaAnalysis/go/goAnalysis.js +17 -0
- package/dist/scaAnalysis/go/goParseDeps.js +158 -0
- package/dist/scaAnalysis/go/goReadDepFile.js +23 -0
- package/dist/scaAnalysis/java/analysis.js +105 -0
- package/dist/scaAnalysis/java/index.js +18 -0
- package/dist/scaAnalysis/java/javaBuildDepsParser.js +339 -0
- package/dist/scaAnalysis/python/analysis.js +41 -0
- package/dist/scaAnalysis/python/index.js +10 -0
- package/dist/scaAnalysis/ruby/analysis.js +226 -0
- package/dist/scaAnalysis/ruby/index.js +10 -0
- package/dist/scan/autoDetection.js +50 -1
- package/dist/scan/fileUtils.js +80 -1
- package/dist/scan/formatScanOutput.js +213 -0
- package/dist/scan/help.js +3 -1
- package/dist/scan/models/groupedResultsModel.js +2 -1
- package/dist/scan/models/scanResultsModel.js +3 -1
- package/dist/scan/populateProjectIdAndProjectName.js +2 -1
- package/dist/scan/scan.js +6 -99
- package/dist/scan/scanConfig.js +6 -1
- package/dist/scan/scanController.js +26 -7
- package/dist/scan/scanResults.js +20 -20
- package/dist/utils/commonApi.js +4 -1
- package/dist/utils/oraWrapper.js +5 -1
- package/package.json +12 -7
- package/src/audit/autodetection/autoDetectLanguage.ts +40 -0
- package/src/audit/catalogueApplication/catalogueApplication.js +3 -16
- package/src/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +11 -8
- package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
- package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
- package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
- package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +17 -5
- package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +76 -3
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +122 -40
- package/src/audit/languageAnalysisEngine/report/models/reportLibraryModel.ts +3 -3
- package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +15 -11
- package/src/audit/languageAnalysisEngine/report/models/reportOutputModel.ts +29 -0
- package/src/audit/languageAnalysisEngine/report/models/reportSeverityModel.ts +12 -3
- package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +16 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +3 -3
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +87 -65
- package/src/audit/languageAnalysisEngine/sendSnapshot.js +78 -25
- package/src/commands/audit/auditConfig.ts +12 -3
- package/src/commands/audit/auditController.ts +9 -3
- package/src/commands/audit/processAudit.ts +4 -1
- package/src/commands/scan/processScan.js +10 -4
- package/src/commands/scan/sca/scaAnalysis.js +83 -0
- package/src/common/HTTPClient.js +65 -25
- package/src/common/errorHandling.ts +14 -22
- package/src/common/versionChecker.ts +1 -1
- package/src/constants/constants.js +24 -2
- package/src/constants/locales.js +33 -50
- package/src/constants.js +22 -0
- package/src/lambda/analytics.ts +9 -0
- package/src/lambda/arn.ts +2 -1
- package/src/lambda/lambda.ts +37 -17
- package/src/lambda/types.ts +35 -0
- package/src/lambda/utils.ts +2 -7
- package/src/scaAnalysis/common/formatMessage.js +38 -0
- package/src/scaAnalysis/common/treeUpload.js +30 -0
- package/src/scaAnalysis/go/goAnalysis.js +19 -0
- package/src/scaAnalysis/go/goParseDeps.js +203 -0
- package/src/scaAnalysis/go/goReadDepFile.js +32 -0
- package/src/scaAnalysis/java/analysis.js +142 -0
- package/src/scaAnalysis/java/index.js +21 -0
- package/src/scaAnalysis/java/javaBuildDepsParser.js +404 -0
- package/src/scaAnalysis/python/analysis.js +48 -0
- package/src/scaAnalysis/python/index.js +11 -0
- package/src/scaAnalysis/ruby/analysis.js +282 -0
- package/src/scaAnalysis/ruby/index.js +11 -0
- package/src/scan/autoDetection.js +58 -1
- package/src/scan/fileUtils.js +99 -1
- package/src/scan/formatScanOutput.ts +249 -0
- package/src/scan/help.js +3 -1
- package/src/scan/models/groupedResultsModel.ts +7 -5
- package/src/scan/models/resultContentModel.ts +2 -2
- package/src/scan/models/scanResultsModel.ts +5 -2
- package/src/scan/populateProjectIdAndProjectName.js +3 -1
- package/src/scan/scan.ts +8 -136
- package/src/scan/scanConfig.js +5 -1
- package/src/scan/scanController.js +30 -10
- package/src/scan/scanResults.js +31 -18
- package/src/utils/commonApi.js +4 -1
- package/src/utils/oraWrapper.js +6 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const i18n = require('i18n');
|
|
3
3
|
const fileFinder = require('./fileUtils');
|
|
4
|
+
const languageResolver = require('../audit/languageAnalysisEngine/reduceIdentifiedLanguages');
|
|
5
|
+
const rootFile = require('../audit/languageAnalysisEngine/getProjectRootFilenames');
|
|
4
6
|
const autoDetectFileAndLanguage = async (configToUse) => {
|
|
5
7
|
const entries = await fileFinder.findFile();
|
|
6
8
|
if (entries.length === 1) {
|
|
@@ -9,6 +11,10 @@ const autoDetectFileAndLanguage = async (configToUse) => {
|
|
|
9
11
|
console.log(i18n.__('fileHasWhiteSpacesError'));
|
|
10
12
|
process.exit(1);
|
|
11
13
|
}
|
|
14
|
+
if (fileFinder.fileIsEmpty(entries[0])) {
|
|
15
|
+
console.log(i18n.__('scanFileIsEmpty'));
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
12
18
|
configToUse.file = entries[0];
|
|
13
19
|
if (configToUse.name === undefined) {
|
|
14
20
|
configToUse.name = entries[0];
|
|
@@ -18,6 +24,31 @@ const autoDetectFileAndLanguage = async (configToUse) => {
|
|
|
18
24
|
errorOnFileDetection(entries);
|
|
19
25
|
}
|
|
20
26
|
};
|
|
27
|
+
const autoDetectAuditFilesAndLanguages = async () => {
|
|
28
|
+
let languagesFound = [];
|
|
29
|
+
console.log(i18n.__('searchingAuditFileDirectory', process.cwd()));
|
|
30
|
+
await fileFinder.findFilesJava(languagesFound);
|
|
31
|
+
await fileFinder.findFilesJavascript(languagesFound);
|
|
32
|
+
await fileFinder.findFilesPython(languagesFound);
|
|
33
|
+
await fileFinder.findFilesGo(languagesFound);
|
|
34
|
+
await fileFinder.findFilesPhp(languagesFound);
|
|
35
|
+
await fileFinder.findFilesRuby(languagesFound);
|
|
36
|
+
if (languagesFound.length === 1) {
|
|
37
|
+
return languagesFound;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
console.log('found multiple languages, please specify one using --file to run SCA analysis');
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const manualDetectAuditFilesAndLanguages = projectPath => {
|
|
44
|
+
let projectRootFilenames = rootFile.getProjectRootFilenames(projectPath);
|
|
45
|
+
let identifiedLanguages = languageResolver.deduceLanguageScaAnalysis(projectRootFilenames);
|
|
46
|
+
if (Object.keys(identifiedLanguages).length === 0) {
|
|
47
|
+
console.log(i18n.__('languageAnalysisNoLanguage', projectPath));
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
return [identifiedLanguages];
|
|
51
|
+
};
|
|
21
52
|
const hasWhiteSpace = s => {
|
|
22
53
|
const filename = s.split('/').pop();
|
|
23
54
|
return filename.indexOf(' ') >= 0;
|
|
@@ -38,7 +69,25 @@ const errorOnFileDetection = entries => {
|
|
|
38
69
|
}
|
|
39
70
|
process.exit(1);
|
|
40
71
|
};
|
|
72
|
+
const errorOnAuditFileDetection = entries => {
|
|
73
|
+
if (entries.length > 1) {
|
|
74
|
+
console.log(i18n.__('searchingDirectoryScan'));
|
|
75
|
+
for (let file in entries) {
|
|
76
|
+
console.log('-', entries[file]);
|
|
77
|
+
}
|
|
78
|
+
console.log('');
|
|
79
|
+
console.log(i18n.__('specifyFileAuditNotFound'));
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
console.log(i18n.__('noFileFoundScan'));
|
|
83
|
+
console.log('');
|
|
84
|
+
console.log(i18n.__('specifyFileAuditNotFound'));
|
|
85
|
+
}
|
|
86
|
+
};
|
|
41
87
|
module.exports = {
|
|
42
88
|
autoDetectFileAndLanguage,
|
|
43
|
-
errorOnFileDetection
|
|
89
|
+
errorOnFileDetection,
|
|
90
|
+
autoDetectAuditFilesAndLanguages,
|
|
91
|
+
errorOnAuditFileDetection,
|
|
92
|
+
manualDetectAuditFilesAndLanguages
|
|
44
93
|
};
|
package/dist/scan/fileUtils.js
CHANGED
|
@@ -10,6 +10,72 @@ const findFile = async () => {
|
|
|
10
10
|
onlyFiles: true
|
|
11
11
|
});
|
|
12
12
|
};
|
|
13
|
+
const findFilesJava = async (languagesFound) => {
|
|
14
|
+
const result = await fg(['**/pom.xml', '**/build.gradle', '**/build.gradle.kts'], {
|
|
15
|
+
dot: false,
|
|
16
|
+
deep: 1,
|
|
17
|
+
onlyFiles: true
|
|
18
|
+
});
|
|
19
|
+
if (result.length > 0) {
|
|
20
|
+
return languagesFound.push({ JAVA: result });
|
|
21
|
+
}
|
|
22
|
+
return languagesFound;
|
|
23
|
+
};
|
|
24
|
+
const findFilesJavascript = async (languagesFound) => {
|
|
25
|
+
const result = await fg(['**/package.json', '**/yarn.lock', '**/package.lock.json'], {
|
|
26
|
+
dot: false,
|
|
27
|
+
deep: 1,
|
|
28
|
+
onlyFiles: true
|
|
29
|
+
});
|
|
30
|
+
if (result.length > 0) {
|
|
31
|
+
return languagesFound.push({ JAVASCRIPT: result });
|
|
32
|
+
}
|
|
33
|
+
return languagesFound;
|
|
34
|
+
};
|
|
35
|
+
const findFilesPython = async (languagesFound) => {
|
|
36
|
+
const result = await fg(['**/Pipfile.lock', '**/Pipfile'], {
|
|
37
|
+
dot: false,
|
|
38
|
+
deep: 3,
|
|
39
|
+
onlyFiles: true
|
|
40
|
+
});
|
|
41
|
+
if (result.length > 0) {
|
|
42
|
+
return languagesFound.push({ PYTHON: result });
|
|
43
|
+
}
|
|
44
|
+
return languagesFound;
|
|
45
|
+
};
|
|
46
|
+
const findFilesGo = async (languagesFound) => {
|
|
47
|
+
const result = await fg(['**/go.mod'], {
|
|
48
|
+
dot: false,
|
|
49
|
+
deep: 3,
|
|
50
|
+
onlyFiles: true
|
|
51
|
+
});
|
|
52
|
+
if (result.length > 0) {
|
|
53
|
+
return languagesFound.push({ GO: result });
|
|
54
|
+
}
|
|
55
|
+
return languagesFound;
|
|
56
|
+
};
|
|
57
|
+
const findFilesRuby = async (languagesFound) => {
|
|
58
|
+
const result = await fg(['**/Gemfile', '**/Gemfile.lock'], {
|
|
59
|
+
dot: false,
|
|
60
|
+
deep: 3,
|
|
61
|
+
onlyFiles: true
|
|
62
|
+
});
|
|
63
|
+
if (result.length > 0) {
|
|
64
|
+
return languagesFound.push({ RUBY: result });
|
|
65
|
+
}
|
|
66
|
+
return languagesFound;
|
|
67
|
+
};
|
|
68
|
+
const findFilesPhp = async (languagesFound) => {
|
|
69
|
+
const result = await fg(['**/composer.json', '**/composer.lock'], {
|
|
70
|
+
dot: false,
|
|
71
|
+
deep: 3,
|
|
72
|
+
onlyFiles: true
|
|
73
|
+
});
|
|
74
|
+
if (result.length > 0) {
|
|
75
|
+
return languagesFound.push({ PHP: result });
|
|
76
|
+
}
|
|
77
|
+
return languagesFound;
|
|
78
|
+
};
|
|
13
79
|
const checkFilePermissions = file => {
|
|
14
80
|
let readableFile = false;
|
|
15
81
|
try {
|
|
@@ -24,8 +90,21 @@ const checkFilePermissions = file => {
|
|
|
24
90
|
const fileExists = path => {
|
|
25
91
|
return fs.existsSync(path);
|
|
26
92
|
};
|
|
93
|
+
const fileIsEmpty = path => {
|
|
94
|
+
if (fileExists(path) && checkFilePermissions(path)) {
|
|
95
|
+
return fs.readFileSync(path).length === 0;
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
};
|
|
27
99
|
module.exports = {
|
|
28
100
|
findFile,
|
|
29
101
|
fileExists,
|
|
30
|
-
checkFilePermissions
|
|
102
|
+
checkFilePermissions,
|
|
103
|
+
findFilesJava,
|
|
104
|
+
findFilesJavascript,
|
|
105
|
+
findFilesPython,
|
|
106
|
+
findFilesGo,
|
|
107
|
+
findFilesPhp,
|
|
108
|
+
findFilesRuby,
|
|
109
|
+
fileIsEmpty
|
|
31
110
|
};
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.assignBySeverity = exports.stripTags = exports.getCodeFlowInfo = exports.getSourceLineNumber = exports.getLocationsSyncInfo = exports.editVulName = exports.getDefaultView = exports.formatLinks = exports.getProjectOverview = exports.formatScanOutput = void 0;
|
|
7
|
+
const i18n_1 = __importDefault(require("i18n"));
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const groupedResultsModel_1 = require("./models/groupedResultsModel");
|
|
10
|
+
const lodash_1 = require("lodash");
|
|
11
|
+
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
12
|
+
const constants_1 = require("../constants/constants");
|
|
13
|
+
function formatScanOutput(scanResults) {
|
|
14
|
+
const { scanResultsInstances } = scanResults;
|
|
15
|
+
const projectOverview = getProjectOverview(scanResultsInstances);
|
|
16
|
+
if (scanResultsInstances.content.length === 0) {
|
|
17
|
+
console.log(i18n_1.default.__('scanNoVulnerabilitiesFound'));
|
|
18
|
+
console.log(i18n_1.default.__('scanNoVulnerabilitiesFoundSecureCode'));
|
|
19
|
+
console.log(i18n_1.default.__('scanNoVulnerabilitiesFoundGoodWork'));
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
const message = projectOverview.critical || projectOverview.high
|
|
23
|
+
? 'Here are your top priorities to fix'
|
|
24
|
+
: "No major issues, here's what we found";
|
|
25
|
+
console.log(chalk_1.default.bold(message));
|
|
26
|
+
console.log();
|
|
27
|
+
let defaultView = getDefaultView(scanResultsInstances.content);
|
|
28
|
+
let count = defaultView.length;
|
|
29
|
+
defaultView.forEach(entry => {
|
|
30
|
+
let table = new cli_table3_1.default({
|
|
31
|
+
chars: {
|
|
32
|
+
top: '',
|
|
33
|
+
'top-mid': '',
|
|
34
|
+
'top-left': '',
|
|
35
|
+
'top-right': '',
|
|
36
|
+
bottom: '',
|
|
37
|
+
'bottom-mid': '',
|
|
38
|
+
'bottom-left': '',
|
|
39
|
+
'bottom-right': '',
|
|
40
|
+
left: '',
|
|
41
|
+
'left-mid': '',
|
|
42
|
+
mid: '',
|
|
43
|
+
'mid-mid': '',
|
|
44
|
+
right: '',
|
|
45
|
+
'right-mid': '',
|
|
46
|
+
middle: ' '
|
|
47
|
+
},
|
|
48
|
+
style: { 'padding-left': 0, 'padding-right': 0 },
|
|
49
|
+
colAligns: ['right'],
|
|
50
|
+
wordWrap: true,
|
|
51
|
+
colWidths: [12, 1, 100]
|
|
52
|
+
});
|
|
53
|
+
let learnRow = [];
|
|
54
|
+
let adviceRow = [];
|
|
55
|
+
const headerRow = [
|
|
56
|
+
chalk_1.default
|
|
57
|
+
.hex(entry.colour)
|
|
58
|
+
.bold(`CONTRAST-${count.toString().padStart(3, '0')}`),
|
|
59
|
+
chalk_1.default.hex(entry.colour).bold('-'),
|
|
60
|
+
chalk_1.default.hex(entry.colour).bold(`[${entry.severity}] ${entry.ruleId}`) +
|
|
61
|
+
entry.message
|
|
62
|
+
];
|
|
63
|
+
const codePath = entry.codePath?.replace(/^@/, '');
|
|
64
|
+
const codeRow = [
|
|
65
|
+
chalk_1.default.hex('#F6F5F5').bold(`Code`),
|
|
66
|
+
chalk_1.default.hex('#F6F5F5').bold(`:`),
|
|
67
|
+
chalk_1.default.hex('#F6F5F5').bold(`${codePath}`)
|
|
68
|
+
];
|
|
69
|
+
const issueRow = [chalk_1.default.bold(`Issue`), chalk_1.default.bold(`:`), `${entry.issue}`];
|
|
70
|
+
table.push(headerRow, codeRow, issueRow);
|
|
71
|
+
if (entry?.advice) {
|
|
72
|
+
adviceRow = [
|
|
73
|
+
chalk_1.default.bold('Advice'),
|
|
74
|
+
chalk_1.default.bold(`:`),
|
|
75
|
+
stripTags(entry.advice)
|
|
76
|
+
];
|
|
77
|
+
table.push(adviceRow);
|
|
78
|
+
}
|
|
79
|
+
if (entry?.learn && entry?.learn.length > 0) {
|
|
80
|
+
learnRow = [
|
|
81
|
+
chalk_1.default.bold('Learn'),
|
|
82
|
+
chalk_1.default.bold(`:`),
|
|
83
|
+
chalk_1.default.hex('#97f7f7').bold.underline(entry.learn[0])
|
|
84
|
+
];
|
|
85
|
+
table.push(learnRow);
|
|
86
|
+
}
|
|
87
|
+
count--;
|
|
88
|
+
console.log(table.toString());
|
|
89
|
+
console.log();
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
printVulnInfo(projectOverview);
|
|
93
|
+
}
|
|
94
|
+
exports.formatScanOutput = formatScanOutput;
|
|
95
|
+
function printVulnInfo(projectOverview) {
|
|
96
|
+
const totalVulnerabilities = projectOverview.total;
|
|
97
|
+
const vulMessage = totalVulnerabilities === 1 ? `vulnerability` : `vulnerabilities`;
|
|
98
|
+
console.log(chalk_1.default.bold(`Found ${totalVulnerabilities} ${vulMessage}`));
|
|
99
|
+
console.log(i18n_1.default.__('foundDetailedVulnerabilities', String(projectOverview.critical), String(projectOverview.high), String(projectOverview.medium), String(projectOverview.low), String(projectOverview.note)));
|
|
100
|
+
}
|
|
101
|
+
function getProjectOverview(scanResultsInstances) {
|
|
102
|
+
const acc = {
|
|
103
|
+
critical: 0,
|
|
104
|
+
high: 0,
|
|
105
|
+
medium: 0,
|
|
106
|
+
low: 0,
|
|
107
|
+
note: 0,
|
|
108
|
+
total: 0
|
|
109
|
+
};
|
|
110
|
+
if (scanResultsInstances?.content &&
|
|
111
|
+
scanResultsInstances.content.length > 0) {
|
|
112
|
+
scanResultsInstances.content.forEach((i) => {
|
|
113
|
+
acc[i.severity.toLowerCase()] += 1;
|
|
114
|
+
acc.total += 1;
|
|
115
|
+
return acc;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return acc;
|
|
119
|
+
}
|
|
120
|
+
exports.getProjectOverview = getProjectOverview;
|
|
121
|
+
function formatLinks(objName, entry) {
|
|
122
|
+
const line = chalk_1.default.bold(objName + ' : ');
|
|
123
|
+
if (entry.length === 1) {
|
|
124
|
+
console.log(line + chalk_1.default.hex('#97DCF7').bold.underline(entry[0]));
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
console.log(line);
|
|
128
|
+
entry.forEach(link => {
|
|
129
|
+
console.log(chalk_1.default.hex('#97DCF7').bold.underline(link));
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.formatLinks = formatLinks;
|
|
134
|
+
function getDefaultView(content) {
|
|
135
|
+
const groupTypeResults = [];
|
|
136
|
+
content.forEach(resultEntry => {
|
|
137
|
+
const groupResultsObj = new groupedResultsModel_1.GroupedResultsModel(resultEntry.ruleId);
|
|
138
|
+
groupResultsObj.severity = resultEntry.severity;
|
|
139
|
+
groupResultsObj.ruleId = resultEntry.ruleId;
|
|
140
|
+
groupResultsObj.issue = stripTags(resultEntry.issue);
|
|
141
|
+
groupResultsObj.advice = resultEntry.advice;
|
|
142
|
+
groupResultsObj.learn = resultEntry.learn;
|
|
143
|
+
groupResultsObj.message = resultEntry.message?.text
|
|
144
|
+
? editVulName(resultEntry.message.text) +
|
|
145
|
+
':' +
|
|
146
|
+
getSourceLineNumber(resultEntry)
|
|
147
|
+
: '';
|
|
148
|
+
groupResultsObj.codePath = getLocationsSyncInfo(resultEntry);
|
|
149
|
+
groupTypeResults.push(groupResultsObj);
|
|
150
|
+
assignBySeverity(resultEntry, groupResultsObj);
|
|
151
|
+
});
|
|
152
|
+
return (0, lodash_1.sortBy)(groupTypeResults, ['priority']).reverse();
|
|
153
|
+
}
|
|
154
|
+
exports.getDefaultView = getDefaultView;
|
|
155
|
+
function editVulName(message) {
|
|
156
|
+
return message.substring(message.indexOf(' in '));
|
|
157
|
+
}
|
|
158
|
+
exports.editVulName = editVulName;
|
|
159
|
+
function getLocationsSyncInfo(resultEntry) {
|
|
160
|
+
const locationsMessage = resultEntry.locations[0]?.physicalLocation?.artifactLocation?.uri || '';
|
|
161
|
+
const locationsLineNumber = resultEntry.locations[0]?.physicalLocation?.region?.startLine || '';
|
|
162
|
+
if (!locationsLineNumber) {
|
|
163
|
+
return '@' + locationsMessage;
|
|
164
|
+
}
|
|
165
|
+
return '@' + locationsMessage + ':' + locationsLineNumber;
|
|
166
|
+
}
|
|
167
|
+
exports.getLocationsSyncInfo = getLocationsSyncInfo;
|
|
168
|
+
function getSourceLineNumber(resultEntry) {
|
|
169
|
+
const locationsLineNumber = resultEntry.locations[0]?.physicalLocation?.region?.startLine || '';
|
|
170
|
+
let codeFlowLineNumber = getCodeFlowInfo(resultEntry);
|
|
171
|
+
return codeFlowLineNumber ? codeFlowLineNumber : locationsLineNumber;
|
|
172
|
+
}
|
|
173
|
+
exports.getSourceLineNumber = getSourceLineNumber;
|
|
174
|
+
function getCodeFlowInfo(resultEntry) {
|
|
175
|
+
let result;
|
|
176
|
+
resultEntry.codeFlows[0]?.threadFlows.forEach((i) => {
|
|
177
|
+
return (result = i.locations.find((locations) => locations.importance === 'essential'));
|
|
178
|
+
});
|
|
179
|
+
return result?.location?.physicalLocation?.region?.startLine;
|
|
180
|
+
}
|
|
181
|
+
exports.getCodeFlowInfo = getCodeFlowInfo;
|
|
182
|
+
function stripTags(oldString) {
|
|
183
|
+
return oldString.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
|
|
184
|
+
}
|
|
185
|
+
exports.stripTags = stripTags;
|
|
186
|
+
function assignBySeverity(entry, assignedObj) {
|
|
187
|
+
if (entry.severity.toUpperCase() === 'CRITICAL') {
|
|
188
|
+
assignedObj.priority = 1;
|
|
189
|
+
assignedObj.colour = constants_1.CRITICAL_COLOUR;
|
|
190
|
+
return assignedObj;
|
|
191
|
+
}
|
|
192
|
+
else if (entry.severity.toUpperCase() === 'HIGH') {
|
|
193
|
+
assignedObj.priority = 2;
|
|
194
|
+
assignedObj.colour = constants_1.HIGH_COLOUR;
|
|
195
|
+
return assignedObj;
|
|
196
|
+
}
|
|
197
|
+
else if (entry.severity.toUpperCase() === 'MEDIUM') {
|
|
198
|
+
assignedObj.priority = 3;
|
|
199
|
+
assignedObj.colour = constants_1.MEDIUM_COLOUR;
|
|
200
|
+
return assignedObj;
|
|
201
|
+
}
|
|
202
|
+
else if (entry.severity.toUpperCase() === 'LOW') {
|
|
203
|
+
assignedObj.priority = 4;
|
|
204
|
+
assignedObj.colour = constants_1.LOW_COLOUR;
|
|
205
|
+
return assignedObj;
|
|
206
|
+
}
|
|
207
|
+
else if (entry.severity.toUpperCase() === 'NOTE') {
|
|
208
|
+
assignedObj.priority = 5;
|
|
209
|
+
assignedObj.colour = constants_1.NOTE_COLOUR;
|
|
210
|
+
return assignedObj;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
exports.assignBySeverity = assignBySeverity;
|
package/dist/scan/help.js
CHANGED
|
@@ -4,7 +4,8 @@ exports.GroupedResultsModel = void 0;
|
|
|
4
4
|
class GroupedResultsModel {
|
|
5
5
|
constructor(ruleId) {
|
|
6
6
|
this.ruleId = ruleId;
|
|
7
|
-
this.
|
|
7
|
+
this.colour = '#999999';
|
|
8
|
+
this.codePathSet = new Set();
|
|
8
9
|
}
|
|
9
10
|
}
|
|
10
11
|
exports.GroupedResultsModel = GroupedResultsModel;
|
|
@@ -5,7 +5,9 @@ class ScanResultsModel {
|
|
|
5
5
|
constructor(scan) {
|
|
6
6
|
this.projectOverview = scan.projectOverview;
|
|
7
7
|
this.scanDetail = scan.scanDetail;
|
|
8
|
-
this.scanResultsInstances =
|
|
8
|
+
this.scanResultsInstances =
|
|
9
|
+
scan.scanResultsInstances;
|
|
10
|
+
this.newProject = scan.newProject;
|
|
9
11
|
}
|
|
10
12
|
}
|
|
11
13
|
exports.ScanResultsModel = ScanResultsModel;
|
|
@@ -8,8 +8,9 @@ const populateProjectId = async (config) => {
|
|
|
8
8
|
proj = await getExistingProjectIdByName(config, client).then(res => {
|
|
9
9
|
return res;
|
|
10
10
|
});
|
|
11
|
+
return { projectId: proj, isNewProject: false };
|
|
11
12
|
}
|
|
12
|
-
return proj;
|
|
13
|
+
return { projectId: proj, isNewProject: true };
|
|
13
14
|
};
|
|
14
15
|
const createProjectId = async (config, client) => {
|
|
15
16
|
return client
|
package/dist/scan/scan.js
CHANGED
|
@@ -3,13 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.sendScan = exports.isFileAllowed = exports.allowedFileTypes = void 0;
|
|
7
7
|
const commonApi_js_1 = __importDefault(require("../utils/commonApi.js"));
|
|
8
8
|
const fileUtils_1 = __importDefault(require("../scan/fileUtils"));
|
|
9
9
|
const i18n_1 = __importDefault(require("i18n"));
|
|
10
10
|
const oraWrapper_1 = __importDefault(require("../utils/oraWrapper"));
|
|
11
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
-
const groupedResultsModel_1 = require("./models/groupedResultsModel");
|
|
13
11
|
exports.allowedFileTypes = ['.jar', '.war', '.js', '.zip', '.exe'];
|
|
14
12
|
const isFileAllowed = (scanOption) => {
|
|
15
13
|
let valid = false;
|
|
@@ -43,114 +41,23 @@ const sendScan = async (config) => {
|
|
|
43
41
|
}
|
|
44
42
|
else {
|
|
45
43
|
if (config.debug) {
|
|
46
|
-
console.log(res.statusCode);
|
|
47
44
|
console.log(config);
|
|
45
|
+
oraWrapper_1.default.failSpinner(startUploadSpinner, i18n_1.default.__('uploadingScanFail'));
|
|
46
|
+
console.log(i18n_1.default.__('genericServiceError', res.statusCode));
|
|
48
47
|
}
|
|
49
|
-
oraWrapper_1.default.failSpinner(startUploadSpinner, i18n_1.default.__('uploadingScanFail'));
|
|
50
48
|
if (res.statusCode === 403) {
|
|
51
49
|
console.log(i18n_1.default.__('permissionsError'));
|
|
52
50
|
process.exit(1);
|
|
53
51
|
}
|
|
54
|
-
|
|
52
|
+
oraWrapper_1.default.stopSpinner(startUploadSpinner);
|
|
53
|
+
console.log('Contrast Scan Finished');
|
|
55
54
|
process.exit(1);
|
|
56
55
|
}
|
|
57
56
|
})
|
|
58
57
|
.catch(err => {
|
|
58
|
+
oraWrapper_1.default.stopSpinner(startUploadSpinner);
|
|
59
59
|
console.log(err);
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
63
|
exports.sendScan = sendScan;
|
|
64
|
-
function formatScanOutput(scanResults) {
|
|
65
|
-
const { projectOverview, scanResultsInstances } = scanResults;
|
|
66
|
-
if (scanResultsInstances.content.length === 0) {
|
|
67
|
-
console.log(i18n_1.default.__('scanNoVulnerabilitiesFound'));
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
const message = projectOverview.critical || projectOverview.high
|
|
71
|
-
? 'Here are your top priorities to fix'
|
|
72
|
-
: "No major issues, here's what we found";
|
|
73
|
-
console.log(chalk_1.default.bold(message));
|
|
74
|
-
console.log();
|
|
75
|
-
const groups = getGroups(scanResultsInstances.content);
|
|
76
|
-
groups.forEach(entry => {
|
|
77
|
-
console.log(chalk_1.default.bold(`[ ${entry.severity} ] | ${entry.ruleId} (${entry.lineInfoSet.size}) - ` +
|
|
78
|
-
`${entry.message}`));
|
|
79
|
-
let count = 1;
|
|
80
|
-
entry.lineInfoSet.forEach(lineInfo => {
|
|
81
|
-
console.log(`\t ${count}. ${lineInfo}`);
|
|
82
|
-
count++;
|
|
83
|
-
});
|
|
84
|
-
if (entry?.issue) {
|
|
85
|
-
console.log(chalk_1.default.bold('Issue' + ': ') + entry.issue);
|
|
86
|
-
}
|
|
87
|
-
if (entry?.advice) {
|
|
88
|
-
console.log(chalk_1.default.bold('Advice' + ': ') + entry.advice);
|
|
89
|
-
}
|
|
90
|
-
if (entry?.learn && entry?.learn.length > 0) {
|
|
91
|
-
formatLinks('Learn', entry.learn);
|
|
92
|
-
}
|
|
93
|
-
console.log();
|
|
94
|
-
});
|
|
95
|
-
printVulnInfo(projectOverview);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
exports.formatScanOutput = formatScanOutput;
|
|
99
|
-
function printVulnInfo(projectOverview) {
|
|
100
|
-
const totalVulnerabilities = getTotalVulns(projectOverview);
|
|
101
|
-
const vulMessage = totalVulnerabilities === 1 ? `vulnerability` : `vulnerabilities`;
|
|
102
|
-
console.log(chalk_1.default.bold(`Found ${totalVulnerabilities} ${vulMessage}`));
|
|
103
|
-
console.log(i18n_1.default.__('foundDetailedVulnerabilities', String(projectOverview.critical), String(projectOverview.high), String(projectOverview.medium), String(projectOverview.low), String(projectOverview.note)));
|
|
104
|
-
}
|
|
105
|
-
function getTotalVulns(projectOverview) {
|
|
106
|
-
return (projectOverview.critical +
|
|
107
|
-
projectOverview.high +
|
|
108
|
-
projectOverview.medium +
|
|
109
|
-
projectOverview.low +
|
|
110
|
-
projectOverview.note);
|
|
111
|
-
}
|
|
112
|
-
function formatLinks(objName, entry) {
|
|
113
|
-
console.log(chalk_1.default.bold(objName + ':'));
|
|
114
|
-
entry.forEach(link => {
|
|
115
|
-
console.log(link);
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
exports.formatLinks = formatLinks;
|
|
119
|
-
function getGroups(content) {
|
|
120
|
-
const groupTypeSet = new Set(content.map(({ ruleId }) => ruleId));
|
|
121
|
-
const groupTypeResults = [];
|
|
122
|
-
groupTypeSet.forEach(groupName => {
|
|
123
|
-
const groupResultsObj = new groupedResultsModel_1.GroupedResultsModel(groupName);
|
|
124
|
-
content.forEach(resultEntry => {
|
|
125
|
-
if (resultEntry.ruleId === groupName) {
|
|
126
|
-
groupResultsObj.severity = resultEntry.severity;
|
|
127
|
-
groupResultsObj.issue = stripMustacheTags(resultEntry.issue);
|
|
128
|
-
groupResultsObj.advice = resultEntry.advice;
|
|
129
|
-
groupResultsObj.learn = resultEntry.learn;
|
|
130
|
-
groupResultsObj.message = resultEntry.message?.text;
|
|
131
|
-
groupResultsObj.lineInfoSet.add(getMessage(resultEntry.locations));
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
groupTypeResults.push(groupResultsObj);
|
|
135
|
-
});
|
|
136
|
-
return groupTypeResults;
|
|
137
|
-
}
|
|
138
|
-
exports.getGroups = getGroups;
|
|
139
|
-
function getMessage(locations) {
|
|
140
|
-
const message = locations[0]?.physicalLocation?.artifactLocation?.uri || '';
|
|
141
|
-
const lineNumber = locations[0]?.physicalLocation?.region?.startLine || '';
|
|
142
|
-
if (!lineNumber) {
|
|
143
|
-
return '@' + message;
|
|
144
|
-
}
|
|
145
|
-
return '@' + message + ':' + lineNumber;
|
|
146
|
-
}
|
|
147
|
-
exports.getMessage = getMessage;
|
|
148
|
-
function stripMustacheTags(oldString) {
|
|
149
|
-
return oldString
|
|
150
|
-
.replace(/\n/g, ' ')
|
|
151
|
-
.replace(/{{.*?}}/g, '\n')
|
|
152
|
-
.replace(/\$\$LINK_DELIM\$\$/g, '\n')
|
|
153
|
-
.replace(/\s+/g, ' ')
|
|
154
|
-
.trim();
|
|
155
|
-
}
|
|
156
|
-
exports.stripMustacheTags = stripMustacheTags;
|
package/dist/scan/scanConfig.js
CHANGED
|
@@ -21,10 +21,15 @@ const getScanConfig = argv => {
|
|
|
21
21
|
process.exit(1);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
let projectNameSource;
|
|
24
25
|
if (!scanParams.name && scanParams.file) {
|
|
25
26
|
scanParams.name = getFileName(scanParams.file);
|
|
27
|
+
projectNameSource = 'AUTO';
|
|
26
28
|
}
|
|
27
|
-
|
|
29
|
+
else {
|
|
30
|
+
projectNameSource = 'USER';
|
|
31
|
+
}
|
|
32
|
+
return { ...paramsAuth, ...scanParams, projectNameSource };
|
|
28
33
|
};
|
|
29
34
|
const getFileName = file => {
|
|
30
35
|
return file.split(path.sep).pop();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const i18n = require('i18n');
|
|
3
|
-
const { returnOra, startSpinner, succeedSpinner } = require('../utils/oraWrapper');
|
|
3
|
+
const { returnOra, startSpinner, succeedSpinner, stopSpinner } = require('../utils/oraWrapper');
|
|
4
4
|
const populateProjectIdAndProjectName = require('./populateProjectIdAndProjectName');
|
|
5
5
|
const scan = require('./scan');
|
|
6
6
|
const scanResults = require('./scanResults');
|
|
@@ -24,6 +24,10 @@ const fileAndLanguageLogic = async (configToUse) => {
|
|
|
24
24
|
console.log(i18n.__('fileNotExist'));
|
|
25
25
|
process.exit(1);
|
|
26
26
|
}
|
|
27
|
+
if (fileFunctions.fileIsEmpty(configToUse.file)) {
|
|
28
|
+
console.log(i18n.__('scanFileIsEmpty'));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
27
31
|
return configToUse;
|
|
28
32
|
}
|
|
29
33
|
else {
|
|
@@ -35,21 +39,36 @@ const fileAndLanguageLogic = async (configToUse) => {
|
|
|
35
39
|
const startScan = async (configToUse) => {
|
|
36
40
|
const startTime = performance.now();
|
|
37
41
|
await fileAndLanguageLogic(configToUse);
|
|
42
|
+
let newProject;
|
|
38
43
|
if (!configToUse.projectId) {
|
|
39
|
-
|
|
44
|
+
const { projectId, isNewProject } = await populateProjectIdAndProjectName.populateProjectId(configToUse);
|
|
45
|
+
configToUse.projectId = projectId;
|
|
46
|
+
newProject = isNewProject;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
newProject = false;
|
|
40
50
|
}
|
|
41
51
|
const codeArtifactId = await scan.sendScan(configToUse);
|
|
42
52
|
if (!configToUse.ff) {
|
|
43
53
|
const startScanSpinner = returnOra('🚀 Contrast Scan started');
|
|
44
54
|
startSpinner(startScanSpinner);
|
|
45
|
-
const scanDetail = await scanResults.returnScanResults(configToUse, codeArtifactId, getTimeout(configToUse), startScanSpinner);
|
|
55
|
+
const scanDetail = await scanResults.returnScanResults(configToUse, codeArtifactId, newProject, getTimeout(configToUse), startScanSpinner);
|
|
46
56
|
const scanResultsInstances = await scanResults.returnScanResultsInstances(configToUse, scanDetail.id);
|
|
47
57
|
const endTime = performance.now();
|
|
48
58
|
const scanDurationMs = endTime - startTime;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
if (scanResultsInstances.statusCode !== 200) {
|
|
60
|
+
stopSpinner(startScanSpinner);
|
|
61
|
+
console.log('Result Service is unavailable, please try again later');
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
succeedSpinner(startScanSpinner, 'Contrast Scan complete');
|
|
66
|
+
console.log(`----- Scan completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
|
|
67
|
+
return {
|
|
68
|
+
scanDetail,
|
|
69
|
+
scanResultsInstances: scanResultsInstances.body
|
|
70
|
+
};
|
|
71
|
+
}
|
|
53
72
|
}
|
|
54
73
|
};
|
|
55
74
|
module.exports = {
|