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