@contrast/contrast 1.0.4 → 1.0.5
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 +2 -0
- package/dist/audit/autodetection/autoDetectLanguage.js +32 -0
- package/dist/audit/catalogueApplication/catalogueApplication.js +2 -11
- package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +4 -2
- package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +25 -0
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +3 -17
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +1 -1
- package/dist/audit/languageAnalysisEngine/sendSnapshot.js +2 -16
- package/dist/commands/audit/auditConfig.js +8 -2
- package/dist/commands/audit/auditController.js +8 -2
- package/dist/commands/scan/processScan.js +6 -3
- package/dist/commands/scan/sca/scaAnalysis.js +44 -0
- package/dist/common/HTTPClient.js +0 -1
- package/dist/common/errorHandling.js +7 -17
- package/dist/constants/constants.js +14 -2
- package/dist/constants/locales.js +28 -35
- package/dist/constants.js +20 -0
- package/dist/scaAnalysis/common/formatMessage.js +11 -0
- package/dist/scaAnalysis/common/treeUpload.js +30 -0
- package/dist/scaAnalysis/java/analysis.js +116 -0
- package/dist/scaAnalysis/java/index.js +18 -0
- package/dist/scaAnalysis/java/javaBuildDepsParser.js +326 -0
- package/dist/scan/autoDetection.js +46 -1
- package/dist/scan/fileUtils.js +73 -1
- package/dist/scan/formatScanOutput.js +212 -0
- package/dist/scan/help.js +3 -1
- package/dist/scan/models/groupedResultsModel.js +2 -1
- package/dist/scan/scan.js +1 -96
- package/dist/scan/scanController.js +1 -2
- package/dist/scan/scanResults.js +3 -17
- package/package.json +2 -1
- package/src/audit/autodetection/autoDetectLanguage.ts +40 -0
- package/src/audit/catalogueApplication/catalogueApplication.js +4 -16
- package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +9 -5
- package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +71 -0
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +3 -25
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +1 -1
- package/src/audit/languageAnalysisEngine/sendSnapshot.js +2 -24
- package/src/commands/audit/auditConfig.ts +12 -3
- package/src/commands/audit/auditController.ts +9 -2
- package/src/commands/audit/processAudit.ts +3 -0
- package/src/commands/scan/processScan.js +8 -3
- package/src/commands/scan/sca/scaAnalysis.js +73 -0
- package/src/common/HTTPClient.js +1 -1
- package/src/common/errorHandling.ts +7 -24
- package/src/constants/constants.js +14 -2
- package/src/constants/locales.js +30 -49
- package/src/constants.js +22 -0
- package/src/scaAnalysis/common/formatMessage.js +10 -0
- package/src/scaAnalysis/common/treeUpload.js +34 -0
- package/src/scaAnalysis/java/analysis.js +159 -0
- package/src/scaAnalysis/java/index.js +21 -0
- package/src/scaAnalysis/java/javaBuildDepsParser.js +391 -0
- package/src/scan/autoDetection.js +54 -1
- package/src/scan/fileUtils.js +91 -1
- package/src/scan/formatScanOutput.ts +241 -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/scan.ts +0 -130
- package/src/scan/scanController.js +1 -2
- package/src/scan/scanResults.js +9 -17
|
@@ -0,0 +1,212 @@
|
|
|
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.content);
|
|
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(content) {
|
|
101
|
+
let acc = {
|
|
102
|
+
critical: 0,
|
|
103
|
+
high: 0,
|
|
104
|
+
medium: 0,
|
|
105
|
+
low: 0,
|
|
106
|
+
note: 0,
|
|
107
|
+
total: 0
|
|
108
|
+
};
|
|
109
|
+
content.forEach((i) => {
|
|
110
|
+
acc[i.severity.toLowerCase()] += 1;
|
|
111
|
+
acc.total += 1;
|
|
112
|
+
return acc;
|
|
113
|
+
});
|
|
114
|
+
return acc;
|
|
115
|
+
}
|
|
116
|
+
exports.getProjectOverview = getProjectOverview;
|
|
117
|
+
function formatLinks(objName, entry) {
|
|
118
|
+
let line = chalk_1.default.bold(objName + ' : ');
|
|
119
|
+
if (entry.length === 1) {
|
|
120
|
+
console.log(line + chalk_1.default.hex('#97DCF7').bold.underline(entry[0]));
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
console.log(line);
|
|
124
|
+
entry.forEach(link => {
|
|
125
|
+
console.log(chalk_1.default.hex('#97DCF7').bold.underline(link));
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.formatLinks = formatLinks;
|
|
130
|
+
function getDefaultView(content) {
|
|
131
|
+
const groupTypeResults = [];
|
|
132
|
+
content.forEach(resultEntry => {
|
|
133
|
+
const groupResultsObj = new groupedResultsModel_1.GroupedResultsModel(resultEntry.ruleId);
|
|
134
|
+
groupResultsObj.severity = resultEntry.severity;
|
|
135
|
+
groupResultsObj.ruleId = resultEntry.ruleId;
|
|
136
|
+
groupResultsObj.issue = stripTags(resultEntry.issue);
|
|
137
|
+
groupResultsObj.advice = resultEntry.advice;
|
|
138
|
+
groupResultsObj.learn = resultEntry.learn;
|
|
139
|
+
groupResultsObj.message = resultEntry.message?.text
|
|
140
|
+
? editVulName(resultEntry.message.text) +
|
|
141
|
+
':' +
|
|
142
|
+
getSourceLineNumber(resultEntry)
|
|
143
|
+
: '';
|
|
144
|
+
groupResultsObj.codePath = getLocationsSyncInfo(resultEntry);
|
|
145
|
+
groupTypeResults.push(groupResultsObj);
|
|
146
|
+
assignBySeverity(resultEntry, groupResultsObj);
|
|
147
|
+
});
|
|
148
|
+
return (0, lodash_1.sortBy)(groupTypeResults, ['priority']).reverse();
|
|
149
|
+
}
|
|
150
|
+
exports.getDefaultView = getDefaultView;
|
|
151
|
+
function editVulName(message) {
|
|
152
|
+
return message.substring(message.indexOf(' in '));
|
|
153
|
+
}
|
|
154
|
+
exports.editVulName = editVulName;
|
|
155
|
+
function getLocationsSyncInfo(resultEntry) {
|
|
156
|
+
const locationsMessage = resultEntry.locations[0]?.physicalLocation?.artifactLocation?.uri || '';
|
|
157
|
+
const locationsLineNumber = resultEntry.locations[0]?.physicalLocation?.region?.startLine || '';
|
|
158
|
+
if (!locationsLineNumber) {
|
|
159
|
+
return '@' + locationsMessage;
|
|
160
|
+
}
|
|
161
|
+
return '@' + locationsMessage + ':' + locationsLineNumber;
|
|
162
|
+
}
|
|
163
|
+
exports.getLocationsSyncInfo = getLocationsSyncInfo;
|
|
164
|
+
function getSourceLineNumber(resultEntry) {
|
|
165
|
+
const locationsLineNumber = resultEntry.locations[0]?.physicalLocation?.region?.startLine || '';
|
|
166
|
+
let codeFlowLineNumber = getCodeFlowInfo(resultEntry);
|
|
167
|
+
return codeFlowLineNumber ? codeFlowLineNumber : locationsLineNumber;
|
|
168
|
+
}
|
|
169
|
+
exports.getSourceLineNumber = getSourceLineNumber;
|
|
170
|
+
function getCodeFlowInfo(resultEntry) {
|
|
171
|
+
let result;
|
|
172
|
+
resultEntry.codeFlows[0]?.threadFlows.forEach((i) => {
|
|
173
|
+
return (result = i.locations.find((locations) => locations.importance === 'essential'));
|
|
174
|
+
});
|
|
175
|
+
return result?.location?.physicalLocation?.region?.startLine;
|
|
176
|
+
}
|
|
177
|
+
exports.getCodeFlowInfo = getCodeFlowInfo;
|
|
178
|
+
function stripTags(oldString) {
|
|
179
|
+
return oldString
|
|
180
|
+
.replace(/\n/g, ' ')
|
|
181
|
+
.replace(/\s+/g, ' ')
|
|
182
|
+
.trim();
|
|
183
|
+
}
|
|
184
|
+
exports.stripTags = stripTags;
|
|
185
|
+
function assignBySeverity(entry, assignedObj) {
|
|
186
|
+
if (entry.severity.toUpperCase() === 'CRITICAL') {
|
|
187
|
+
assignedObj.priority = 1;
|
|
188
|
+
assignedObj.colour = constants_1.CRITICAL_COLOUR;
|
|
189
|
+
return assignedObj;
|
|
190
|
+
}
|
|
191
|
+
else if (entry.severity.toUpperCase() === 'HIGH') {
|
|
192
|
+
assignedObj.priority = 2;
|
|
193
|
+
assignedObj.colour = constants_1.HIGH_COLOUR;
|
|
194
|
+
return assignedObj;
|
|
195
|
+
}
|
|
196
|
+
else if (entry.severity.toUpperCase() === 'MEDIUM') {
|
|
197
|
+
assignedObj.priority = 3;
|
|
198
|
+
assignedObj.colour = constants_1.MEDIUM_COLOUR;
|
|
199
|
+
return assignedObj;
|
|
200
|
+
}
|
|
201
|
+
else if (entry.severity.toUpperCase() === 'LOW') {
|
|
202
|
+
assignedObj.priority = 4;
|
|
203
|
+
assignedObj.colour = constants_1.LOW_COLOUR;
|
|
204
|
+
return assignedObj;
|
|
205
|
+
}
|
|
206
|
+
else if (entry.severity.toUpperCase() === 'NOTE') {
|
|
207
|
+
assignedObj.priority = 5;
|
|
208
|
+
assignedObj.colour = constants_1.NOTE_COLOUR;
|
|
209
|
+
return assignedObj;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
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;
|
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;
|
|
@@ -61,96 +59,3 @@ const sendScan = async (config) => {
|
|
|
61
59
|
}
|
|
62
60
|
};
|
|
63
61
|
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;
|
|
@@ -48,8 +48,7 @@ const startScan = async (configToUse) => {
|
|
|
48
48
|
const scanDurationMs = endTime - startTime;
|
|
49
49
|
succeedSpinner(startScanSpinner, 'Contrast Scan complete');
|
|
50
50
|
console.log(`----- Scan completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
|
|
51
|
-
|
|
52
|
-
return { projectOverview, scanDetail, scanResultsInstances };
|
|
51
|
+
return { scanDetail, scanResultsInstances };
|
|
53
52
|
}
|
|
54
53
|
};
|
|
55
54
|
module.exports = {
|
package/dist/scan/scanResults.js
CHANGED
|
@@ -40,8 +40,8 @@ const returnScanResults = async (config, codeArtifactId, timeout, startScanSpinn
|
|
|
40
40
|
}
|
|
41
41
|
if (result.body.status === 'FAILED') {
|
|
42
42
|
complete = true;
|
|
43
|
-
oraFunctions.failSpinner(startScanSpinner, '
|
|
44
|
-
console.log(result.body.errorMessage);
|
|
43
|
+
oraFunctions.failSpinner(startScanSpinner, i18n.__('scanNotCompleted', 'https://docs.contrastsecurity.com/en/binary-package-preparation.html'));
|
|
44
|
+
result.body.errorMessage ? console.log(result.body.errorMessage) : '';
|
|
45
45
|
if (result.body.errorMessage ===
|
|
46
46
|
'Unable to determine language for code artifact') {
|
|
47
47
|
console.log('Try scanning again using --language param. ', i18n.__('scanOptionsLanguageSummary'));
|
|
@@ -71,23 +71,9 @@ const returnScanResultsInstances = async (config, scanId) => {
|
|
|
71
71
|
console.log(e.message.toString());
|
|
72
72
|
}
|
|
73
73
|
};
|
|
74
|
-
const returnScanProjectById = async (config) => {
|
|
75
|
-
const client = commonApi.getHttpClient(config);
|
|
76
|
-
let result;
|
|
77
|
-
try {
|
|
78
|
-
result = await client.getScanProjectById(config);
|
|
79
|
-
if (JSON.stringify(result.statusCode) == 200) {
|
|
80
|
-
return result.body;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
catch (e) {
|
|
84
|
-
console.log(e.message.toString());
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
74
|
module.exports = {
|
|
88
75
|
getScanId: getScanId,
|
|
89
76
|
returnScanResults: returnScanResults,
|
|
90
77
|
pollScanResults: pollScanResults,
|
|
91
|
-
returnScanResultsInstances: returnScanResultsInstances
|
|
92
|
-
returnScanProjectById: returnScanProjectById
|
|
78
|
+
returnScanResultsInstances: returnScanResultsInstances
|
|
93
79
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/contrast",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Contrast Security's command line tool",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"bluebird": "^3.7.2",
|
|
46
46
|
"boxen": "5.1.2",
|
|
47
47
|
"chalk": "4.1.2",
|
|
48
|
+
"cli-table3": "^0.6.2",
|
|
48
49
|
"command-line-args": "^5.2.1",
|
|
49
50
|
"command-line-usage": "^6.1.3",
|
|
50
51
|
"conf": "^10.1.2",
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import i18n from 'i18n'
|
|
3
|
+
import {
|
|
4
|
+
reduceIdentifiedLanguages,
|
|
5
|
+
deduceLanguage
|
|
6
|
+
} from '../languageAnalysisEngine/reduceIdentifiedLanguages'
|
|
7
|
+
|
|
8
|
+
import { getProjectRootFilenames } from '../languageAnalysisEngine/getProjectRootFilenames'
|
|
9
|
+
|
|
10
|
+
export function identifyLanguages(config: any) {
|
|
11
|
+
const { projectPath } = config
|
|
12
|
+
const projectRootFilenames = getProjectRootFilenames(projectPath)
|
|
13
|
+
|
|
14
|
+
const identifiedLanguages = projectRootFilenames.reduce(
|
|
15
|
+
(accumulator: any, filename: string) => {
|
|
16
|
+
const deducedLanguages = deduceLanguage(filename)
|
|
17
|
+
return [...accumulator, ...deducedLanguages]
|
|
18
|
+
},
|
|
19
|
+
[]
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
if (Object.keys(identifiedLanguages).length === 0) {
|
|
23
|
+
throw new Error(i18n.__('languageAnalysisNoLanguage', projectPath))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return reduceIdentifiedLanguages(identifiedLanguages)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function determineProjectLanguage(
|
|
30
|
+
reducedLanguages: Record<string, string>
|
|
31
|
+
) {
|
|
32
|
+
const reducedLanguagesKeys = Object.keys(reducedLanguages)
|
|
33
|
+
if (reducedLanguagesKeys.length === 1) {
|
|
34
|
+
return reducedLanguagesKeys[0]
|
|
35
|
+
} else {
|
|
36
|
+
throw new Error(
|
|
37
|
+
'Detected multiple languages. Please specify a single language using --language'
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -1,21 +1,8 @@
|
|
|
1
1
|
const i18n = require('i18n')
|
|
2
2
|
const { getHttpClient, handleResponseErrors } = require('../../utils/commonApi')
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const displaySuccessMessage = (config, appId) => {
|
|
9
|
-
console.log(
|
|
10
|
-
'\n **************************' +
|
|
11
|
-
i18n.__('successHeader') +
|
|
12
|
-
'************************** \n'
|
|
13
|
-
)
|
|
14
|
-
console.log('\n' + i18n.__('catalogueSuccessCommand') + appId + '\n')
|
|
15
|
-
console.log(locationOfApp(config, appId))
|
|
16
|
-
console.log(
|
|
17
|
-
'\n *********************************************************** \n'
|
|
18
|
-
)
|
|
4
|
+
const displaySuccessMessage = () => {
|
|
5
|
+
console.log(i18n.__('catalogueSuccessCommand'))
|
|
19
6
|
}
|
|
20
7
|
|
|
21
8
|
const catalogueApplication = async config => {
|
|
@@ -25,9 +12,10 @@ const catalogueApplication = async config => {
|
|
|
25
12
|
.catalogueCommand(config)
|
|
26
13
|
.then(res => {
|
|
27
14
|
if (res.statusCode === 201) {
|
|
28
|
-
displaySuccessMessage(config, res.body.application.app_id)
|
|
15
|
+
//displaySuccessMessage(config, res.body.application.app_id)
|
|
29
16
|
appId = res.body.application.app_id
|
|
30
17
|
} else {
|
|
18
|
+
// console.log(res.statusCode)
|
|
31
19
|
handleResponseErrors(res, 'catalogue')
|
|
32
20
|
}
|
|
33
21
|
})
|
|
@@ -15,6 +15,12 @@ const fs = require('fs')
|
|
|
15
15
|
const chalk = require('chalk')
|
|
16
16
|
const saveFile = require('../../commands/audit/saveFile').default
|
|
17
17
|
const generateSbom = require('../../sbom/generateSbom').default
|
|
18
|
+
const {
|
|
19
|
+
failSpinner,
|
|
20
|
+
returnOra,
|
|
21
|
+
startSpinner,
|
|
22
|
+
succeedSpinner
|
|
23
|
+
} = require('../../utils/oraWrapper')
|
|
18
24
|
|
|
19
25
|
module.exports = exports = (err, analysis) => {
|
|
20
26
|
const { identifiedLanguageInfo } = analysis.languageAnalysis
|
|
@@ -45,17 +51,15 @@ module.exports = exports = (err, analysis) => {
|
|
|
45
51
|
return process.exit(5)
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'))
|
|
55
|
+
startSpinner(reportSpinner)
|
|
49
56
|
const snapshotResponse = await newSendSnapShot(analysis, catalogueAppId)
|
|
57
|
+
succeedSpinner(reportSpinner, 'Contrast SCA analysis complete')
|
|
50
58
|
|
|
51
59
|
await vulnerabilityReport(analysis, catalogueAppId, snapshotResponse.id)
|
|
52
60
|
|
|
53
61
|
//should be moved to processAudit.ts once promises implemented
|
|
54
62
|
await auditSave(config)
|
|
55
|
-
|
|
56
|
-
console.log(
|
|
57
|
-
'\n ***************CONTRAST OSS ANALYSIS COMPLETE************** \n'
|
|
58
|
-
)
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
if (identifiedLanguageInfo.language === DOTNET) {
|
|
@@ -28,6 +28,76 @@ const isRubyLockFilename = filename => filename === 'Gemfile.lock'
|
|
|
28
28
|
const isPipfileLockLockFilename = filename => filename === 'Pipfile.lock'
|
|
29
29
|
const isGoProjectFilename = filename => filename === 'go.mod'
|
|
30
30
|
|
|
31
|
+
const deduceLanguageScaAnalysis = filenames => {
|
|
32
|
+
const deducedLanguages = []
|
|
33
|
+
let language = ''
|
|
34
|
+
|
|
35
|
+
filenames.forEach(filename => {
|
|
36
|
+
// Check for project filenames...
|
|
37
|
+
if (isJavaMavenProjectFilename(filename)) {
|
|
38
|
+
deducedLanguages.push(filename)
|
|
39
|
+
language = JAVA
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (isJavaGradleProjectFilename(filename)) {
|
|
43
|
+
deducedLanguages.push(filename)
|
|
44
|
+
language = JAVA
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (isNodeProjectFilename(filename)) {
|
|
48
|
+
deducedLanguages.push(filename)
|
|
49
|
+
language = NODE
|
|
50
|
+
}
|
|
51
|
+
//
|
|
52
|
+
// if (isDotNetProjectFilename(filename)) {
|
|
53
|
+
// deducedLanguages.push({language: DOTNET, projectFilename: filename})
|
|
54
|
+
// }
|
|
55
|
+
//
|
|
56
|
+
// if (isRubyProjectFilename(filename)) {
|
|
57
|
+
// deducedLanguages.push({language: RUBY, projectFilename: filename})
|
|
58
|
+
// }
|
|
59
|
+
//
|
|
60
|
+
// if (isPythonProjectFilename(filename)) {
|
|
61
|
+
// deducedLanguages.push({language: PYTHON, projectFilename: filename})
|
|
62
|
+
// }
|
|
63
|
+
//
|
|
64
|
+
// if (isPhpProjectFilename(filename)) {
|
|
65
|
+
// deducedLanguages.push({language: PHP, projectFilename: filename})
|
|
66
|
+
// }
|
|
67
|
+
//
|
|
68
|
+
// // Check for lock filenames...
|
|
69
|
+
// if (isDotNetLockFilename(filename)) {
|
|
70
|
+
// deducedLanguages.push({language: DOTNET, lockFilename: filename})
|
|
71
|
+
// }
|
|
72
|
+
//
|
|
73
|
+
if (isNodeLockFilename(filename)) {
|
|
74
|
+
deducedLanguages.push(filename)
|
|
75
|
+
language = node
|
|
76
|
+
}
|
|
77
|
+
//
|
|
78
|
+
// if (isRubyLockFilename(filename)) {
|
|
79
|
+
// deducedLanguages.push({language: RUBY, lockFilename: filename})
|
|
80
|
+
// }
|
|
81
|
+
//
|
|
82
|
+
// // this is pipfileLock rather than python lock as there can be different python locks
|
|
83
|
+
// if (isPipfileLockLockFilename(filename)) {
|
|
84
|
+
// deducedLanguages.push({language: PYTHON, lockFilename: filename})
|
|
85
|
+
// }
|
|
86
|
+
//
|
|
87
|
+
// if (isPhpLockFilename(filename)) {
|
|
88
|
+
// deducedLanguages.push({language: PHP, lockFilename: filename})
|
|
89
|
+
// }
|
|
90
|
+
//
|
|
91
|
+
// // go does not have a lockfile, it should have a go.mod file containing the modules
|
|
92
|
+
// if (isGoProjectFilename(filename)) {
|
|
93
|
+
// deducedLanguages.push({language: GO, projectFilename: filename})
|
|
94
|
+
// }
|
|
95
|
+
})
|
|
96
|
+
let identifiedLanguages = { [language]: deducedLanguages }
|
|
97
|
+
|
|
98
|
+
return identifiedLanguages
|
|
99
|
+
}
|
|
100
|
+
|
|
31
101
|
const deduceLanguage = filename => {
|
|
32
102
|
const deducedLanguages = []
|
|
33
103
|
|
|
@@ -175,3 +245,4 @@ exports.isPhpProjectFilename = isPhpProjectFilename
|
|
|
175
245
|
exports.isPhpLockFilename = isPhpLockFilename
|
|
176
246
|
exports.deduceLanguage = deduceLanguage
|
|
177
247
|
exports.reduceIdentifiedLanguages = reduceIdentifiedLanguages
|
|
248
|
+
exports.deduceLanguageScaAnalysis = deduceLanguageScaAnalysis
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import i18n from 'i18n'
|
|
2
1
|
import { getHttpClient, handleResponseErrors } from '../../../utils/commonApi'
|
|
3
2
|
import {
|
|
4
3
|
ReportCompositeKey,
|
|
@@ -10,50 +9,29 @@ import { orderBy } from 'lodash'
|
|
|
10
9
|
import chalk from 'chalk'
|
|
11
10
|
import { ReportLibraryModel } from './models/reportLibraryModel'
|
|
12
11
|
import { findHighestSeverityCVE, findNameAndVersion } from './utils/reportUtils'
|
|
13
|
-
import {
|
|
14
|
-
failSpinner,
|
|
15
|
-
returnOra,
|
|
16
|
-
startSpinner,
|
|
17
|
-
succeedSpinner
|
|
18
|
-
} from '../../../utils/oraWrapper'
|
|
19
12
|
|
|
20
13
|
export const createLibraryHeader = (
|
|
21
14
|
id: string,
|
|
22
15
|
numberOfVulnerableLibraries: number,
|
|
23
|
-
numberOfCves: number
|
|
24
|
-
name: string
|
|
16
|
+
numberOfCves: number
|
|
25
17
|
) => {
|
|
26
|
-
name
|
|
27
|
-
? console.log(`\n Application Name: ${name} | Application ID: ${id}`)
|
|
28
|
-
: console.log(` Application ID: ${id}`)
|
|
29
|
-
|
|
30
18
|
numberOfVulnerableLibraries === 1
|
|
31
19
|
? console.log(
|
|
32
|
-
|
|
33
|
-
` Found 1 vulnerable library containing ${numberOfCves} CVE's` +
|
|
34
|
-
'************************** '
|
|
20
|
+
` Found 1 vulnerable library containing ${numberOfCves} CVE's`
|
|
35
21
|
)
|
|
36
22
|
: console.log(
|
|
37
|
-
|
|
38
|
-
` Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVE's ` +
|
|
39
|
-
'************************** '
|
|
23
|
+
` Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVE's `
|
|
40
24
|
)
|
|
41
25
|
}
|
|
42
26
|
|
|
43
27
|
export const getReport = async (config: any, reportId: string) => {
|
|
44
28
|
const client = getHttpClient(config)
|
|
45
|
-
|
|
46
|
-
const reportSpinner = returnOra(i18n.__('auditReportWaiting'))
|
|
47
|
-
reportSpinner.indent = 1
|
|
48
|
-
startSpinner(reportSpinner)
|
|
49
29
|
return client
|
|
50
30
|
.getReportById(config, reportId)
|
|
51
31
|
.then((res: { statusCode: number; body: any }) => {
|
|
52
32
|
if (res.statusCode === 200) {
|
|
53
|
-
succeedSpinner(reportSpinner, i18n.__('auditReportSuccessMessage'))
|
|
54
33
|
return res.body
|
|
55
34
|
} else {
|
|
56
|
-
failSpinner(reportSpinner, i18n.__('auditReportFail'))
|
|
57
35
|
console.log('config-------------------')
|
|
58
36
|
console.log(config)
|
|
59
37
|
console.log('reportId----------------')
|
|
@@ -41,7 +41,7 @@ export function formatVulnerabilityOutput(
|
|
|
41
41
|
let numberOfCves = 0
|
|
42
42
|
vulnerableLibraries.forEach(lib => (numberOfCves += lib.cveArray.length))
|
|
43
43
|
|
|
44
|
-
createLibraryHeader(id, numberOfVulnerableLibraries, numberOfCves
|
|
44
|
+
createLibraryHeader(id, numberOfVulnerableLibraries, numberOfCves)
|
|
45
45
|
|
|
46
46
|
const hasSomeVulnerabilitiesReported = printVulnerabilityResponse(
|
|
47
47
|
vulnerableLibraries,
|