@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.
Files changed (62) hide show
  1. package/.prettierignore +2 -0
  2. package/dist/audit/autodetection/autoDetectLanguage.js +32 -0
  3. package/dist/audit/catalogueApplication/catalogueApplication.js +2 -11
  4. package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +4 -2
  5. package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +25 -0
  6. package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +3 -17
  7. package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +1 -1
  8. package/dist/audit/languageAnalysisEngine/sendSnapshot.js +2 -16
  9. package/dist/commands/audit/auditConfig.js +8 -2
  10. package/dist/commands/audit/auditController.js +8 -2
  11. package/dist/commands/scan/processScan.js +6 -3
  12. package/dist/commands/scan/sca/scaAnalysis.js +44 -0
  13. package/dist/common/HTTPClient.js +0 -1
  14. package/dist/common/errorHandling.js +7 -17
  15. package/dist/constants/constants.js +14 -2
  16. package/dist/constants/locales.js +28 -35
  17. package/dist/constants.js +20 -0
  18. package/dist/scaAnalysis/common/formatMessage.js +11 -0
  19. package/dist/scaAnalysis/common/treeUpload.js +30 -0
  20. package/dist/scaAnalysis/java/analysis.js +116 -0
  21. package/dist/scaAnalysis/java/index.js +18 -0
  22. package/dist/scaAnalysis/java/javaBuildDepsParser.js +326 -0
  23. package/dist/scan/autoDetection.js +46 -1
  24. package/dist/scan/fileUtils.js +73 -1
  25. package/dist/scan/formatScanOutput.js +212 -0
  26. package/dist/scan/help.js +3 -1
  27. package/dist/scan/models/groupedResultsModel.js +2 -1
  28. package/dist/scan/scan.js +1 -96
  29. package/dist/scan/scanController.js +1 -2
  30. package/dist/scan/scanResults.js +3 -17
  31. package/package.json +2 -1
  32. package/src/audit/autodetection/autoDetectLanguage.ts +40 -0
  33. package/src/audit/catalogueApplication/catalogueApplication.js +4 -16
  34. package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +9 -5
  35. package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +71 -0
  36. package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +3 -25
  37. package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +1 -1
  38. package/src/audit/languageAnalysisEngine/sendSnapshot.js +2 -24
  39. package/src/commands/audit/auditConfig.ts +12 -3
  40. package/src/commands/audit/auditController.ts +9 -2
  41. package/src/commands/audit/processAudit.ts +3 -0
  42. package/src/commands/scan/processScan.js +8 -3
  43. package/src/commands/scan/sca/scaAnalysis.js +73 -0
  44. package/src/common/HTTPClient.js +1 -1
  45. package/src/common/errorHandling.ts +7 -24
  46. package/src/constants/constants.js +14 -2
  47. package/src/constants/locales.js +30 -49
  48. package/src/constants.js +22 -0
  49. package/src/scaAnalysis/common/formatMessage.js +10 -0
  50. package/src/scaAnalysis/common/treeUpload.js +34 -0
  51. package/src/scaAnalysis/java/analysis.js +159 -0
  52. package/src/scaAnalysis/java/index.js +21 -0
  53. package/src/scaAnalysis/java/javaBuildDepsParser.js +391 -0
  54. package/src/scan/autoDetection.js +54 -1
  55. package/src/scan/fileUtils.js +91 -1
  56. package/src/scan/formatScanOutput.ts +241 -0
  57. package/src/scan/help.js +3 -1
  58. package/src/scan/models/groupedResultsModel.ts +7 -5
  59. package/src/scan/models/resultContentModel.ts +2 -2
  60. package/src/scan/scan.ts +0 -130
  61. package/src/scan/scanController.js +1 -2
  62. 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
@@ -30,7 +30,9 @@ const scanUsageGuide = commandLineUsage([
30
30
  'ff',
31
31
  'ignore-cert-errors',
32
32
  'verbose',
33
- 'debug'
33
+ 'debug',
34
+ 'experimental',
35
+ 'application-name'
34
36
  ]
35
37
  },
36
38
  {
@@ -4,7 +4,8 @@ exports.GroupedResultsModel = void 0;
4
4
  class GroupedResultsModel {
5
5
  constructor(ruleId) {
6
6
  this.ruleId = ruleId;
7
- this.lineInfoSet = new Set;
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.stripMustacheTags = exports.getMessage = exports.getGroups = exports.formatLinks = exports.formatScanOutput = exports.sendScan = exports.isFileAllowed = exports.allowedFileTypes = void 0;
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
- const projectOverview = await scanResults.returnScanProjectById(configToUse);
52
- return { projectOverview, scanDetail, scanResultsInstances };
51
+ return { scanDetail, scanResultsInstances };
53
52
  }
54
53
  };
55
54
  module.exports = {
@@ -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, 'Contrast Scan Failed.');
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.4",
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 locationOfApp = (config, appId) => {
5
- return `${config.host}/Contrast/static/ng/index.html#/${config.organizationId}/applications/${appId}`
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
- console.log('\n **************CONTRAST OSS ANALYSIS BEGINS**************')
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
- '\n **************************' +
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
- '\n **************************' +
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, name)
44
+ createLibraryHeader(id, numberOfVulnerableLibraries, numberOfCves)
45
45
 
46
46
  const hasSomeVulnerabilitiesReported = printVulnerabilityResponse(
47
47
  vulnerableLibraries,