@contrast/contrast 1.0.2 → 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 +4 -0
- package/README.md +24 -16
- package/dist/audit/autodetection/autoDetectLanguage.js +32 -0
- package/dist/audit/catalogueApplication/catalogueApplication.js +2 -11
- package/dist/audit/languageAnalysisEngine/{langugageAnalysisFactory.js → languageAnalysisFactory.js} +30 -13
- package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +25 -0
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +51 -237
- 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/reportSeverityModel.js +10 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +24 -129
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +85 -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/audit/saveFile.js +11 -0
- package/dist/commands/auth/auth.js +19 -1
- package/dist/commands/config/config.js +19 -8
- package/dist/commands/scan/processScan.js +13 -27
- package/dist/commands/scan/sca/scaAnalysis.js +44 -0
- package/dist/common/HTTPClient.js +29 -26
- package/dist/common/errorHandling.js +15 -39
- package/dist/common/versionChecker.js +32 -0
- package/dist/constants/constants.js +16 -2
- package/dist/constants/lambda.js +3 -1
- package/dist/constants/locales.js +58 -48
- package/dist/constants.js +59 -3
- package/dist/index.js +48 -30
- package/dist/lambda/help.js +22 -14
- package/dist/lambda/lambda.js +6 -0
- package/dist/sbom/generateSbom.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 +6 -2
- 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/populateProjectIdAndProjectName.js +1 -0
- package/dist/scan/saveResults.js +9 -10
- package/dist/scan/scan.js +26 -101
- package/dist/scan/scanConfig.js +20 -1
- package/dist/scan/scanController.js +8 -4
- package/dist/scan/scanResults.js +8 -17
- package/dist/utils/getConfig.js +3 -0
- package/dist/utils/requestUtils.js +1 -1
- package/dist/utils/saveFile.js +19 -0
- 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} +41 -19
- package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +71 -0
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +105 -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/reportSeverityModel.ts +9 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +56 -0
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +110 -0
- package/src/audit/languageAnalysisEngine/sendSnapshot.js +2 -22
- package/src/commands/audit/auditConfig.ts +12 -3
- package/src/commands/audit/auditController.ts +21 -5
- package/src/commands/audit/processAudit.ts +3 -1
- package/src/commands/audit/saveFile.ts +6 -0
- package/src/commands/auth/auth.js +25 -1
- package/src/commands/config/config.js +22 -8
- package/src/commands/scan/processScan.js +15 -31
- package/src/commands/scan/sca/scaAnalysis.js +73 -0
- package/src/common/HTTPClient.js +42 -36
- package/src/common/errorHandling.ts +17 -48
- package/src/common/versionChecker.ts +41 -0
- package/src/constants/constants.js +17 -4
- package/src/constants/lambda.js +3 -1
- package/src/constants/locales.js +69 -63
- package/src/constants.js +66 -3
- package/src/index.ts +62 -36
- package/src/lambda/help.ts +22 -14
- package/src/lambda/lambda.ts +8 -0
- package/src/sbom/generateSbom.ts +17 -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 +6 -2
- 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/populateProjectIdAndProjectName.js +1 -0
- package/src/scan/saveResults.js +8 -9
- package/src/scan/scan.ts +62 -0
- package/src/scan/scanConfig.js +26 -1
- package/src/scan/scanController.js +12 -4
- package/src/scan/scanResults.js +19 -17
- package/src/utils/getConfig.ts +12 -0
- package/src/utils/requestUtils.js +1 -1
- package/src/utils/saveFile.js +19 -0
- package/dist/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +0 -17
- package/dist/audit/languageAnalysisEngine/report/newReportingFeature.js +0 -81
- package/dist/common/findLatestCLIVersion.js +0 -23
- 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/common/findLatestCLIVersion.ts +0 -27
- package/src/scan/scan.js +0 -167
package/.prettierignore
CHANGED
package/README.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
# Contrast
|
|
1
|
+
# CodeSec by Contrast Security
|
|
2
|
+
|
|
3
|
+
CodeSec delivers:
|
|
2
4
|
|
|
3
5
|
- The fastest and most accurate SAST scanner.
|
|
4
6
|
- Immediate and actionable results — scan code and serverless environments.
|
|
@@ -7,7 +9,7 @@
|
|
|
7
9
|
|
|
8
10
|
## Install
|
|
9
11
|
|
|
10
|
-
```
|
|
12
|
+
```shell
|
|
11
13
|
npm install -g @contrast/contrast
|
|
12
14
|
```
|
|
13
15
|
|
|
@@ -21,7 +23,8 @@ In the resulting browser window, log in and authenticate with your GitHub or Goo
|
|
|
21
23
|
|
|
22
24
|
### SAST scan
|
|
23
25
|
|
|
24
|
-
####Requirements
|
|
26
|
+
#### Scan Requirements
|
|
27
|
+
|
|
25
28
|
Make sure you have the correct file types to scan.
|
|
26
29
|
|
|
27
30
|
- Upload a .jar or .war file to scan a Java project for analysis
|
|
@@ -34,7 +37,7 @@ Use the Contrast scan command `contrast scan`
|
|
|
34
37
|
|
|
35
38
|
### Lambda function scan
|
|
36
39
|
|
|
37
|
-
####Requirements
|
|
40
|
+
#### Lambda Requirements
|
|
38
41
|
|
|
39
42
|
- Currently supports Java and Python functions on AWS.
|
|
40
43
|
Configure AWS credentials on your local environment by running the commands with your credentials:
|
|
@@ -57,7 +60,7 @@ export AWS_SECRET_ACCESS_KEY=<YOUR_SECRET_ACCESS_KEY>
|
|
|
57
60
|
Use contrast lambda to scan your AWS Lambda functions.
|
|
58
61
|
`contrast lambda --function-name MyFunctionName --region my-aws-region`
|
|
59
62
|
|
|
60
|
-
## Contrast
|
|
63
|
+
## Contrast commands
|
|
61
64
|
|
|
62
65
|
### auth
|
|
63
66
|
|
|
@@ -83,19 +86,24 @@ Performs a security SAST scan.
|
|
|
83
86
|
|
|
84
87
|
**Options:**
|
|
85
88
|
|
|
86
|
-
- **contrast scan --file**
|
|
87
|
-
|
|
89
|
+
- **contrast scan --file**
|
|
90
|
+
|
|
91
|
+
- Path of the file you want to scan. Contrast searches for a .jar, .war, .js. or .zip file in the working directory if a file is not specified.
|
|
92
|
+
- Alias: **--f**
|
|
88
93
|
|
|
89
94
|
- **contrast scan --name**
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
|
|
96
|
+
- Contrast project name. If not specified, Contrast uses contrast.settings to identify the project or creates a project.
|
|
97
|
+
- Alias: **–n**
|
|
98
|
+
|
|
92
99
|
- **contrast scan --save**
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
|
|
101
|
+
- Download the results to a Static Analysis Results Interchange Format (SARIF) file. The file is downloaded to the current working directory with a default name of results.sarif. You can view the file with any text editor.
|
|
102
|
+
- Alias: **-s**
|
|
95
103
|
|
|
96
104
|
- **contrast scan --timeout**
|
|
97
|
-
Time in seconds to wait for the scan to complete. Default value is 300 seconds.
|
|
98
|
-
Alias: **-t**
|
|
105
|
+
- Time in seconds to wait for the scan to complete. Default value is 300 seconds.
|
|
106
|
+
- Alias: **-t**
|
|
99
107
|
|
|
100
108
|
### lambda
|
|
101
109
|
|
|
@@ -105,6 +113,9 @@ Name of AWS lambda function to scan.
|
|
|
105
113
|
|
|
106
114
|
**Options:**
|
|
107
115
|
|
|
116
|
+
- **contrast lambda --list-functions**
|
|
117
|
+
Lists all available lambda functions to scan.
|
|
118
|
+
|
|
108
119
|
- **contrast lambda --function-name --endpoint-url**
|
|
109
120
|
AWS Endpoint override. Similar to AWS CLI.
|
|
110
121
|
Alias: **-e**
|
|
@@ -125,9 +136,6 @@ Name of AWS lambda function to scan.
|
|
|
125
136
|
Returns extended information to the terminal.
|
|
126
137
|
Alias: **-v**
|
|
127
138
|
|
|
128
|
-
- **contrast lambda -–function-name --list-functions**
|
|
129
|
-
Lists all available lambda functions to scan.
|
|
130
|
-
|
|
131
139
|
- **contrast lambda --function-name -–help**
|
|
132
140
|
Displays usage guide.
|
|
133
141
|
Alias: **-h**
|
|
@@ -0,0 +1,32 @@
|
|
|
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.determineProjectLanguage = exports.identifyLanguages = void 0;
|
|
7
|
+
const i18n_1 = __importDefault(require("i18n"));
|
|
8
|
+
const reduceIdentifiedLanguages_1 = require("../languageAnalysisEngine/reduceIdentifiedLanguages");
|
|
9
|
+
const getProjectRootFilenames_1 = require("../languageAnalysisEngine/getProjectRootFilenames");
|
|
10
|
+
function identifyLanguages(config) {
|
|
11
|
+
const { projectPath } = config;
|
|
12
|
+
const projectRootFilenames = (0, getProjectRootFilenames_1.getProjectRootFilenames)(projectPath);
|
|
13
|
+
const identifiedLanguages = projectRootFilenames.reduce((accumulator, filename) => {
|
|
14
|
+
const deducedLanguages = (0, reduceIdentifiedLanguages_1.deduceLanguage)(filename);
|
|
15
|
+
return [...accumulator, ...deducedLanguages];
|
|
16
|
+
}, []);
|
|
17
|
+
if (Object.keys(identifiedLanguages).length === 0) {
|
|
18
|
+
throw new Error(i18n_1.default.__('languageAnalysisNoLanguage', projectPath));
|
|
19
|
+
}
|
|
20
|
+
return (0, reduceIdentifiedLanguages_1.reduceIdentifiedLanguages)(identifiedLanguages);
|
|
21
|
+
}
|
|
22
|
+
exports.identifyLanguages = identifyLanguages;
|
|
23
|
+
function determineProjectLanguage(reducedLanguages) {
|
|
24
|
+
const reducedLanguagesKeys = Object.keys(reducedLanguages);
|
|
25
|
+
if (reducedLanguagesKeys.length === 1) {
|
|
26
|
+
return reducedLanguagesKeys[0];
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
throw new Error('Detected multiple languages. Please specify a single language using --language');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.determineProjectLanguage = determineProjectLanguage;
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const i18n = require('i18n');
|
|
3
3
|
const { getHttpClient, handleResponseErrors } = require('../../utils/commonApi');
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
};
|
|
7
|
-
const displaySuccessMessage = (config, appId) => {
|
|
8
|
-
console.log('\n **************************' +
|
|
9
|
-
i18n.__('successHeader') +
|
|
10
|
-
'************************** \n');
|
|
11
|
-
console.log('\n' + i18n.__('catalogueSuccessCommand') + appId + '\n');
|
|
12
|
-
console.log(locationOfApp(config, appId));
|
|
13
|
-
console.log('\n *********************************************************** \n');
|
|
4
|
+
const displaySuccessMessage = () => {
|
|
5
|
+
console.log(i18n.__('catalogueSuccessCommand'));
|
|
14
6
|
};
|
|
15
7
|
const catalogueApplication = async (config) => {
|
|
16
8
|
const client = getHttpClient(config);
|
|
@@ -19,7 +11,6 @@ const catalogueApplication = async (config) => {
|
|
|
19
11
|
.catalogueCommand(config)
|
|
20
12
|
.then(res => {
|
|
21
13
|
if (res.statusCode === 201) {
|
|
22
|
-
displaySuccessMessage(config, res.body.application.app_id);
|
|
23
14
|
appId = res.body.application.app_id;
|
|
24
15
|
}
|
|
25
16
|
else {
|
package/dist/audit/languageAnalysisEngine/{langugageAnalysisFactory.js → languageAnalysisFactory.js}
RENAMED
|
@@ -9,9 +9,12 @@ const pythonAE = require('../pythonAnalysisEngine');
|
|
|
9
9
|
const phpAE = require('../phpAnalysisEngine');
|
|
10
10
|
const goAE = require('../goAnalysisEngine');
|
|
11
11
|
const { vulnerabilityReport } = require('./report/reportingFeature');
|
|
12
|
-
const { vulnReportWithoutDevDep } = require('./report/newReportingFeature');
|
|
13
|
-
const { checkDevDeps } = require('./report/checkIgnoreDevDep');
|
|
14
12
|
const { newSendSnapShot } = require('../languageAnalysisEngine/sendSnapshot');
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const chalk = require('chalk');
|
|
15
|
+
const saveFile = require('../../commands/audit/saveFile').default;
|
|
16
|
+
const generateSbom = require('../../sbom/generateSbom').default;
|
|
17
|
+
const { failSpinner, returnOra, startSpinner, succeedSpinner } = require('../../utils/oraWrapper');
|
|
15
18
|
module.exports = exports = (err, analysis) => {
|
|
16
19
|
const { identifiedLanguageInfo } = analysis.languageAnalysis;
|
|
17
20
|
const catalogueAppId = analysis.languageAnalysis.appId;
|
|
@@ -33,18 +36,12 @@ module.exports = exports = (err, analysis) => {
|
|
|
33
36
|
err);
|
|
34
37
|
return process.exit(5);
|
|
35
38
|
}
|
|
36
|
-
|
|
39
|
+
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
|
|
40
|
+
startSpinner(reportSpinner);
|
|
37
41
|
const snapshotResponse = await newSendSnapShot(analysis, catalogueAppId);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
await vulnReportWithoutDevDep(analysis, catalogueAppId, snapshotResponse.id, config);
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
await vulnerabilityReport(analysis, catalogueAppId, config);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
console.log('\n ***************CONTRAST OSS ANALYSIS COMPLETE************** \n');
|
|
42
|
+
succeedSpinner(reportSpinner, 'Contrast SCA analysis complete');
|
|
43
|
+
await vulnerabilityReport(analysis, catalogueAppId, snapshotResponse.id);
|
|
44
|
+
await auditSave(config);
|
|
48
45
|
};
|
|
49
46
|
if (identifiedLanguageInfo.language === DOTNET) {
|
|
50
47
|
dotnetAE(identifiedLanguageInfo, analysis.config, langCallback);
|
|
@@ -68,3 +65,23 @@ module.exports = exports = (err, analysis) => {
|
|
|
68
65
|
goAE(identifiedLanguageInfo, analysis.config, langCallback);
|
|
69
66
|
}
|
|
70
67
|
};
|
|
68
|
+
async function auditSave(config) {
|
|
69
|
+
if (config.save) {
|
|
70
|
+
if (config.save.toLowerCase() === 'sbom') {
|
|
71
|
+
saveFile(config, await generateSbom(config));
|
|
72
|
+
const filename = `${config.applicationId}-sbom-cyclonedx.json`;
|
|
73
|
+
if (fs.existsSync(filename)) {
|
|
74
|
+
console.log(i18n.__('auditSBOMSaveSuccess') + ` - ${filename}`);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
console.log(chalk.yellow.bold(`\n Unable to save ${filename} Software Bill of Materials (SBOM)`));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
console.log(i18n.__('auditBadFiletypeSpecifiedForSave'));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else if (config.save === null) {
|
|
85
|
+
console.log(i18n.__('auditNoFiletypeSpecifiedForSave'));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -22,6 +22,30 @@ function isNodeLockFilename(filename) {
|
|
|
22
22
|
const isRubyLockFilename = filename => filename === 'Gemfile.lock';
|
|
23
23
|
const isPipfileLockLockFilename = filename => filename === 'Pipfile.lock';
|
|
24
24
|
const isGoProjectFilename = filename => filename === 'go.mod';
|
|
25
|
+
const deduceLanguageScaAnalysis = filenames => {
|
|
26
|
+
const deducedLanguages = [];
|
|
27
|
+
let language = '';
|
|
28
|
+
filenames.forEach(filename => {
|
|
29
|
+
if (isJavaMavenProjectFilename(filename)) {
|
|
30
|
+
deducedLanguages.push(filename);
|
|
31
|
+
language = JAVA;
|
|
32
|
+
}
|
|
33
|
+
if (isJavaGradleProjectFilename(filename)) {
|
|
34
|
+
deducedLanguages.push(filename);
|
|
35
|
+
language = JAVA;
|
|
36
|
+
}
|
|
37
|
+
if (isNodeProjectFilename(filename)) {
|
|
38
|
+
deducedLanguages.push(filename);
|
|
39
|
+
language = NODE;
|
|
40
|
+
}
|
|
41
|
+
if (isNodeLockFilename(filename)) {
|
|
42
|
+
deducedLanguages.push(filename);
|
|
43
|
+
language = node;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
let identifiedLanguages = { [language]: deducedLanguages };
|
|
47
|
+
return identifiedLanguages;
|
|
48
|
+
};
|
|
25
49
|
const deduceLanguage = filename => {
|
|
26
50
|
const deducedLanguages = [];
|
|
27
51
|
if (isJavaMavenProjectFilename(filename)) {
|
|
@@ -119,3 +143,4 @@ exports.isPhpProjectFilename = isPhpProjectFilename;
|
|
|
119
143
|
exports.isPhpLockFilename = isPhpLockFilename;
|
|
120
144
|
exports.deduceLanguage = deduceLanguage;
|
|
121
145
|
exports.reduceIdentifiedLanguages = reduceIdentifiedLanguages;
|
|
146
|
+
exports.deduceLanguageScaAnalysis = deduceLanguageScaAnalysis;
|
|
@@ -1,257 +1,71 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
function displaySuccessMessageReport() {
|
|
5
|
-
console.log('\n' + i18n.__('reportSuccessMessage'));
|
|
6
|
-
}
|
|
7
|
-
function getAllDependenciesArray(packageJson) {
|
|
8
|
-
const { dependencies, optionalDependencies, devDependencies, peerDependencies } = packageJson;
|
|
9
|
-
const allDep = {
|
|
10
|
-
...dependencies,
|
|
11
|
-
...devDependencies,
|
|
12
|
-
...optionalDependencies,
|
|
13
|
-
...peerDependencies
|
|
14
|
-
};
|
|
15
|
-
return Object.entries(allDep);
|
|
16
|
-
}
|
|
17
|
-
function checkIfDepIsScoped(arrDep) {
|
|
18
|
-
let count = 0;
|
|
19
|
-
arrDep.forEach(([key, value]) => {
|
|
20
|
-
if (!key.startsWith('@')) {
|
|
21
|
-
console.log(` WARNING not scoped: ${key}:${value}`);
|
|
22
|
-
count++;
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
return count;
|
|
26
|
-
}
|
|
27
|
-
const dependencyRiskReport = async (packageJson, config) => {
|
|
28
|
-
const arrDep = getAllDependenciesArray(packageJson);
|
|
29
|
-
const unRegisteredDeps = await checkIfDepIsRegisteredOnNPM(arrDep, config);
|
|
30
|
-
let scopedCount = checkIfDepIsScoped(unRegisteredDeps);
|
|
31
|
-
return {
|
|
32
|
-
scopedCount: scopedCount,
|
|
33
|
-
unRegisteredCount: unRegisteredDeps.length
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
const checkIfDepIsRegisteredOnNPM = async (arrDep, config) => {
|
|
37
|
-
let promises = [];
|
|
38
|
-
let unRegisteredDeps = [];
|
|
39
|
-
const client = getHttpClient(config);
|
|
40
|
-
for (const [index, element] of arrDep) {
|
|
41
|
-
const query = `query artifactByGAV($name: String!, $language: String!, $groupName: String, $version: String!, $nameCheck: Boolean) {
|
|
42
|
-
artifact: exactVersion(name: $name, language: $language, groupName: $groupName, version: $version, nameCheck: $nameCheck) {
|
|
43
|
-
version
|
|
44
|
-
cves {
|
|
45
|
-
baseScore
|
|
46
|
-
}}}`;
|
|
47
|
-
const data = {
|
|
48
|
-
query: query,
|
|
49
|
-
variables: {
|
|
50
|
-
name: index,
|
|
51
|
-
version: element,
|
|
52
|
-
language: 'node',
|
|
53
|
-
nameCheck: true
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
promises.push(client.checkLibrary(data));
|
|
57
|
-
}
|
|
58
|
-
await Promise.all(promises).then(response => {
|
|
59
|
-
response.forEach(res => {
|
|
60
|
-
const libName = JSON.parse(res.request.body);
|
|
61
|
-
if (res.statusCode === 200) {
|
|
62
|
-
if (res.body.data.artifact == null) {
|
|
63
|
-
unRegisteredDeps.push([
|
|
64
|
-
libName.variables.name,
|
|
65
|
-
libName.variables.version
|
|
66
|
-
]);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
if (unRegisteredDeps.length !== 0) {
|
|
72
|
-
console.log('\n Dependencies Risk Report', '\n\n Private libraries that are not scoped. We recommend these libraries are reviewed and the scope claimed to prevent dependency confusion breaches');
|
|
73
|
-
}
|
|
74
|
-
return unRegisteredDeps;
|
|
75
|
-
};
|
|
76
|
-
const createLibraryHeader = (id, numberOfVulnerableLibraries, numberOfCves, name) => {
|
|
77
|
-
name
|
|
78
|
-
? console.log(` Application Name: ${name} | Application ID: ${id}`)
|
|
79
|
-
: console.log(` Application ID: ${id}`);
|
|
80
|
-
console.log(` Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVE's`);
|
|
81
|
-
};
|
|
82
|
-
const breakPipeline = () => {
|
|
83
|
-
failOptionError();
|
|
84
|
-
process.exit(1);
|
|
85
|
-
};
|
|
86
|
-
const parameterOptions = hasSomeVulnerabilitiesReported => {
|
|
87
|
-
const inputtedCLIOptions = cliOptions.getCommandLineArgs();
|
|
88
|
-
let cveSeverityOption = inputtedCLIOptions['cve_severity'];
|
|
89
|
-
let fail = inputtedCLIOptions['fail'];
|
|
90
|
-
let cve_threshold = inputtedCLIOptions['cve_threshold'];
|
|
91
|
-
let expr;
|
|
92
|
-
if (cveSeverityOption && fail && cve_threshold) {
|
|
93
|
-
expr = 'SeverityAndThreshold';
|
|
94
|
-
}
|
|
95
|
-
else if (!cveSeverityOption && fail && cve_threshold) {
|
|
96
|
-
expr = 'ThresholdOnly';
|
|
97
|
-
}
|
|
98
|
-
else if (!cve_threshold && fail && hasSomeVulnerabilitiesReported[0]) {
|
|
99
|
-
expr = 'FailOnly';
|
|
100
|
-
}
|
|
101
|
-
return expr;
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
102
4
|
};
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
criticalSeverity = hasSomeVulnerabilitiesReported[2].critical;
|
|
115
|
-
highSeverity = hasSomeVulnerabilitiesReported[2].high;
|
|
116
|
-
mediumSeverity = hasSomeVulnerabilitiesReported[2].medium;
|
|
117
|
-
lowSeverity = hasSomeVulnerabilitiesReported[2].low;
|
|
118
|
-
if (cveSeverity === 'HIGH') {
|
|
119
|
-
if (cve_threshold < highSeverity + criticalSeverity) {
|
|
120
|
-
breakPipeline();
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
if (cveSeverity === 'MEDIUM') {
|
|
124
|
-
if (cve_threshold < mediumSeverity + highSeverity) {
|
|
125
|
-
breakPipeline();
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
if (cveSeverity === 'LOW') {
|
|
129
|
-
if (cve_threshold < lowSeverity + mediumSeverity + highSeverity) {
|
|
130
|
-
breakPipeline();
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
break;
|
|
134
|
-
case 'ThresholdOnly':
|
|
135
|
-
if (cve_threshold < hasSomeVulnerabilitiesReported[1]) {
|
|
136
|
-
breakPipeline();
|
|
137
|
-
}
|
|
138
|
-
break;
|
|
139
|
-
case 'FailOnly':
|
|
140
|
-
breakPipeline();
|
|
141
|
-
break;
|
|
142
|
-
}
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.printFormattedOutput = exports.printVulnerabilityResponse = exports.getReport = exports.createLibraryHeader = void 0;
|
|
7
|
+
const commonApi_1 = require("../../../utils/commonApi");
|
|
8
|
+
const reportListModel_1 = require("./models/reportListModel");
|
|
9
|
+
const lodash_1 = require("lodash");
|
|
10
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
11
|
+
const reportUtils_1 = require("./utils/reportUtils");
|
|
12
|
+
const createLibraryHeader = (id, numberOfVulnerableLibraries, numberOfCves) => {
|
|
13
|
+
numberOfVulnerableLibraries === 1
|
|
14
|
+
? console.log(` Found 1 vulnerable library containing ${numberOfCves} CVE's`)
|
|
15
|
+
: console.log(` Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVE's `);
|
|
143
16
|
};
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
const protocol = getValidHost(userParams.host);
|
|
148
|
-
const client = commonApi.getHttpClient(userParams, protocol, addParams);
|
|
17
|
+
exports.createLibraryHeader = createLibraryHeader;
|
|
18
|
+
const getReport = async (config, reportId) => {
|
|
19
|
+
const client = (0, commonApi_1.getHttpClient)(config);
|
|
149
20
|
return client
|
|
150
|
-
.
|
|
151
|
-
.then(res => {
|
|
21
|
+
.getReportById(config, reportId)
|
|
22
|
+
.then((res) => {
|
|
152
23
|
if (res.statusCode === 200) {
|
|
153
|
-
displaySuccessMessageReport();
|
|
154
24
|
return res.body;
|
|
155
25
|
}
|
|
156
26
|
else {
|
|
157
|
-
|
|
27
|
+
console.log('config-------------------');
|
|
28
|
+
console.log(config);
|
|
29
|
+
console.log('reportId----------------');
|
|
30
|
+
console.log(reportId);
|
|
31
|
+
console.log(JSON.stringify(res));
|
|
32
|
+
(0, commonApi_1.handleResponseErrors)(res, 'report');
|
|
158
33
|
}
|
|
159
34
|
})
|
|
160
|
-
.catch(err => {
|
|
35
|
+
.catch((err) => {
|
|
161
36
|
console.log(err);
|
|
162
37
|
});
|
|
163
38
|
};
|
|
164
|
-
|
|
39
|
+
exports.getReport = getReport;
|
|
40
|
+
const printVulnerabilityResponse = (vulnerabilities, config) => {
|
|
165
41
|
let hasSomeVulnerabilitiesReported = false;
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
hasSomeVulnerabilitiesReported = true;
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
returnCveData(vulnerabilities);
|
|
173
|
-
if (Object.keys(vulnerabilities).length > 0)
|
|
174
|
-
hasSomeVulnerabilitiesReported = true;
|
|
42
|
+
(0, exports.printFormattedOutput)(vulnerabilities, config);
|
|
43
|
+
if (Object.keys(vulnerabilities).length > 0) {
|
|
44
|
+
hasSomeVulnerabilitiesReported = true;
|
|
175
45
|
}
|
|
176
46
|
return hasSomeVulnerabilitiesReported;
|
|
177
47
|
};
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
const version = nameVersion[1];
|
|
186
|
-
const libName = group !== 'null'
|
|
187
|
-
? `${group}/${name}/${version} is vulnerable`
|
|
188
|
-
: `${name}/${version} is vulnerable`;
|
|
189
|
-
console.log('\n\n ' + libName);
|
|
190
|
-
value.forEach(vuln => {
|
|
191
|
-
let sevCode = vuln.severityCode || vuln.severity_code;
|
|
192
|
-
console.log('\n ' + vuln.name + ' ' + sevCode + '\n ' + vuln.description);
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
function searchHighCVEs(vuln) {
|
|
197
|
-
let sevCode = vuln.severityCode || vuln.severity_code;
|
|
198
|
-
if (sevCode === 'HIGH') {
|
|
199
|
-
return vuln;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
function searchMediumCVEs(vuln) {
|
|
203
|
-
let sevCode = vuln.severityCode || vuln.severity_code;
|
|
204
|
-
if (sevCode === 'HIGH' || sevCode === 'MEDIUM') {
|
|
205
|
-
return vuln;
|
|
48
|
+
exports.printVulnerabilityResponse = printVulnerabilityResponse;
|
|
49
|
+
const printFormattedOutput = (libraries, config) => {
|
|
50
|
+
const report = new reportListModel_1.ReportList();
|
|
51
|
+
for (const library of libraries) {
|
|
52
|
+
const { name, version } = (0, reportUtils_1.findNameAndVersion)(library, config);
|
|
53
|
+
const newOutputModel = new reportListModel_1.ReportModelStructure(new reportListModel_1.ReportCompositeKey(name, version, (0, reportUtils_1.findHighestSeverityCVE)(library.cveArray)), library.cveArray);
|
|
54
|
+
report.reportOutputList.push(newOutputModel);
|
|
206
55
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
56
|
+
const orderedOutputList = (0, lodash_1.orderBy)(report.reportOutputList, reportListItem => reportListItem.compositeKey.highestSeverity.priority);
|
|
57
|
+
for (const reportModel of orderedOutputList) {
|
|
58
|
+
const name = reportModel.compositeKey.libraryName;
|
|
59
|
+
const version = reportModel.compositeKey.libraryVersion;
|
|
60
|
+
const highestSeverity = reportModel.compositeKey.highestSeverity.severity;
|
|
61
|
+
const numOfCVEs = reportModel.cveArray.length;
|
|
62
|
+
const cveNames = [];
|
|
63
|
+
reportModel.cveArray.forEach(cve => cveNames.push(cve.name));
|
|
64
|
+
const boldHeader = chalk_1.default.bold(`${highestSeverity} | Vulnerable Library`);
|
|
65
|
+
const cvePluralised = numOfCVEs > 1 ? 'CVEs' : 'CVE';
|
|
66
|
+
console.log(`\n ${boldHeader} ${name} (${version}) has ${numOfCVEs} known ${cvePluralised}`);
|
|
67
|
+
console.log(` ${cveNames.join(', ')}`);
|
|
68
|
+
console.log(chalk_1.default.bold(' How to fix: Update to latest version'));
|
|
212
69
|
}
|
|
213
|
-
}
|
|
214
|
-
const filterVulnerabilitiesBySeverity = (severity, vulnerabilities) => {
|
|
215
|
-
let filteredVulns = [];
|
|
216
|
-
if (severity) {
|
|
217
|
-
for (let x in vulnerabilities) {
|
|
218
|
-
if (severity.severity === 'HIGH') {
|
|
219
|
-
let highVulnerability = vulnerabilities[x].filter(searchHighCVEs);
|
|
220
|
-
if (highVulnerability.length > 0) {
|
|
221
|
-
filteredVulns[x] = highVulnerability;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
else if (severity.severity === 'MEDIUM') {
|
|
225
|
-
let mediumVulnerability = vulnerabilities[x].filter(searchMediumCVEs);
|
|
226
|
-
if (mediumVulnerability.length > 0) {
|
|
227
|
-
filteredVulns[x] = mediumVulnerability;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
else if (severity.severity === 'LOW') {
|
|
231
|
-
let lowVulnerability = vulnerabilities[x].filter(searchLowCVEs);
|
|
232
|
-
if (lowVulnerability.length > 0) {
|
|
233
|
-
filteredVulns[x] = lowVulnerability;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
return filteredVulns;
|
|
239
|
-
};
|
|
240
|
-
module.exports = {
|
|
241
|
-
displaySuccessMessageReport: displaySuccessMessageReport,
|
|
242
|
-
getAllDependenciesArray: getAllDependenciesArray,
|
|
243
|
-
dependencyRiskReport: dependencyRiskReport,
|
|
244
|
-
createLibraryHeader: createLibraryHeader,
|
|
245
|
-
breakPipeline: breakPipeline,
|
|
246
|
-
parameterOptions: parameterOptions,
|
|
247
|
-
analyseReportOptions: analyseReportOptions,
|
|
248
|
-
getReport: getReport,
|
|
249
|
-
checkIfDepIsScoped: checkIfDepIsScoped,
|
|
250
|
-
checkIfDepIsRegisteredOnNPM: checkIfDepIsRegisteredOnNPM,
|
|
251
|
-
filterVulnerabilitiesBySeverity: filterVulnerabilitiesBySeverity,
|
|
252
|
-
searchLowCVEs: searchLowCVEs,
|
|
253
|
-
searchMediumCVEs: searchMediumCVEs,
|
|
254
|
-
searchHighCVEs: searchHighCVEs,
|
|
255
|
-
returnCveData: returnCveData,
|
|
256
|
-
printVulnerabilityResponse: printVulnerabilityResponse
|
|
257
70
|
};
|
|
71
|
+
exports.printFormattedOutput = printFormattedOutput;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReportCVEModel = exports.ReportLibraryModel = void 0;
|
|
4
|
+
class ReportLibraryModel {
|
|
5
|
+
constructor(name, cveArray) {
|
|
6
|
+
this.name = name;
|
|
7
|
+
this.cveArray = cveArray;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.ReportLibraryModel = ReportLibraryModel;
|
|
11
|
+
class ReportCVEModel {
|
|
12
|
+
constructor(name, description, severityCode, cvss3SeverityCode) {
|
|
13
|
+
this.name = name;
|
|
14
|
+
this.description = description;
|
|
15
|
+
this.severityCode = severityCode;
|
|
16
|
+
this.cvss3SeverityCode = cvss3SeverityCode;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.ReportCVEModel = ReportCVEModel;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReportCompositeKey = exports.ReportModelStructure = exports.ReportList = void 0;
|
|
4
|
+
class ReportList {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.reportOutputList = [];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
exports.ReportList = ReportList;
|
|
10
|
+
class ReportModelStructure {
|
|
11
|
+
constructor(compositeKey, cveArray) {
|
|
12
|
+
this.compositeKey = compositeKey;
|
|
13
|
+
this.cveArray = cveArray;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.ReportModelStructure = ReportModelStructure;
|
|
17
|
+
class ReportCompositeKey {
|
|
18
|
+
constructor(libraryName, libraryVersion, highestSeverity) {
|
|
19
|
+
this.libraryName = libraryName;
|
|
20
|
+
this.libraryVersion = libraryVersion;
|
|
21
|
+
this.highestSeverity = highestSeverity;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.ReportCompositeKey = ReportCompositeKey;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReportSeverityModel = void 0;
|
|
4
|
+
class ReportSeverityModel {
|
|
5
|
+
constructor(severity, priority) {
|
|
6
|
+
this.severity = severity;
|
|
7
|
+
this.priority = priority;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.ReportSeverityModel = ReportSeverityModel;
|