@contrast/contrast 1.0.4 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +0 -3
- package/dist/audit/autodetection/autoDetectLanguage.js +32 -0
- package/dist/audit/catalogueApplication/catalogueApplication.js +2 -11
- package/dist/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +4 -2
- package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
- package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
- package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
- package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +6 -2
- package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +39 -1
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +69 -30
- package/dist/audit/languageAnalysisEngine/report/models/reportOutputModel.js +24 -0
- package/dist/audit/languageAnalysisEngine/report/models/reportSeverityModel.js +3 -1
- package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +13 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +2 -2
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +56 -45
- package/dist/audit/languageAnalysisEngine/sendSnapshot.js +65 -17
- package/dist/commands/audit/auditConfig.js +8 -2
- package/dist/commands/audit/auditController.js +9 -3
- package/dist/commands/audit/processAudit.js +1 -1
- package/dist/commands/scan/processScan.js +7 -4
- package/dist/commands/scan/sca/scaAnalysis.js +60 -0
- package/dist/common/HTTPClient.js +50 -16
- package/dist/common/errorHandling.js +11 -16
- package/dist/common/versionChecker.js +1 -1
- package/dist/constants/constants.js +24 -2
- package/dist/constants/locales.js +31 -36
- package/dist/constants.js +20 -0
- package/dist/lambda/analytics.js +11 -0
- package/dist/lambda/lambda.js +35 -4
- package/dist/lambda/types.js +13 -0
- package/dist/scaAnalysis/common/formatMessage.js +35 -0
- package/dist/scaAnalysis/common/treeUpload.js +29 -0
- package/dist/scaAnalysis/go/goAnalysis.js +17 -0
- package/dist/scaAnalysis/go/goParseDeps.js +158 -0
- package/dist/scaAnalysis/go/goReadDepFile.js +23 -0
- package/dist/scaAnalysis/java/analysis.js +105 -0
- package/dist/scaAnalysis/java/index.js +18 -0
- package/dist/scaAnalysis/java/javaBuildDepsParser.js +339 -0
- package/dist/scaAnalysis/python/analysis.js +41 -0
- package/dist/scaAnalysis/python/index.js +10 -0
- package/dist/scaAnalysis/ruby/analysis.js +226 -0
- package/dist/scaAnalysis/ruby/index.js +10 -0
- package/dist/scan/autoDetection.js +50 -1
- package/dist/scan/fileUtils.js +80 -1
- package/dist/scan/formatScanOutput.js +213 -0
- package/dist/scan/help.js +3 -1
- package/dist/scan/models/groupedResultsModel.js +2 -1
- package/dist/scan/models/scanResultsModel.js +3 -1
- package/dist/scan/populateProjectIdAndProjectName.js +2 -1
- package/dist/scan/scan.js +6 -99
- package/dist/scan/scanConfig.js +6 -1
- package/dist/scan/scanController.js +26 -7
- package/dist/scan/scanResults.js +20 -20
- package/dist/utils/commonApi.js +4 -1
- package/dist/utils/oraWrapper.js +5 -1
- package/package.json +12 -7
- package/src/audit/autodetection/autoDetectLanguage.ts +40 -0
- package/src/audit/catalogueApplication/catalogueApplication.js +3 -16
- package/src/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +11 -8
- package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
- package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
- package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
- package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +17 -5
- package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +76 -3
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +122 -40
- package/src/audit/languageAnalysisEngine/report/models/reportLibraryModel.ts +3 -3
- package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +15 -11
- package/src/audit/languageAnalysisEngine/report/models/reportOutputModel.ts +29 -0
- package/src/audit/languageAnalysisEngine/report/models/reportSeverityModel.ts +12 -3
- package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +16 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +3 -3
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +87 -65
- package/src/audit/languageAnalysisEngine/sendSnapshot.js +78 -25
- package/src/commands/audit/auditConfig.ts +12 -3
- package/src/commands/audit/auditController.ts +9 -3
- package/src/commands/audit/processAudit.ts +4 -1
- package/src/commands/scan/processScan.js +10 -4
- package/src/commands/scan/sca/scaAnalysis.js +83 -0
- package/src/common/HTTPClient.js +65 -25
- package/src/common/errorHandling.ts +14 -22
- package/src/common/versionChecker.ts +1 -1
- package/src/constants/constants.js +24 -2
- package/src/constants/locales.js +33 -50
- package/src/constants.js +22 -0
- package/src/lambda/analytics.ts +9 -0
- package/src/lambda/arn.ts +2 -1
- package/src/lambda/lambda.ts +37 -17
- package/src/lambda/types.ts +35 -0
- package/src/lambda/utils.ts +2 -7
- package/src/scaAnalysis/common/formatMessage.js +38 -0
- package/src/scaAnalysis/common/treeUpload.js +30 -0
- package/src/scaAnalysis/go/goAnalysis.js +19 -0
- package/src/scaAnalysis/go/goParseDeps.js +203 -0
- package/src/scaAnalysis/go/goReadDepFile.js +32 -0
- package/src/scaAnalysis/java/analysis.js +142 -0
- package/src/scaAnalysis/java/index.js +21 -0
- package/src/scaAnalysis/java/javaBuildDepsParser.js +404 -0
- package/src/scaAnalysis/python/analysis.js +48 -0
- package/src/scaAnalysis/python/index.js +11 -0
- package/src/scaAnalysis/ruby/analysis.js +282 -0
- package/src/scaAnalysis/ruby/index.js +11 -0
- package/src/scan/autoDetection.js +58 -1
- package/src/scan/fileUtils.js +99 -1
- package/src/scan/formatScanOutput.ts +249 -0
- package/src/scan/help.js +3 -1
- package/src/scan/models/groupedResultsModel.ts +7 -5
- package/src/scan/models/resultContentModel.ts +2 -2
- package/src/scan/models/scanResultsModel.ts +5 -2
- package/src/scan/populateProjectIdAndProjectName.js +3 -1
- package/src/scan/scan.ts +8 -136
- package/src/scan/scanConfig.js +5 -1
- package/src/scan/scanController.js +30 -10
- package/src/scan/scanResults.js +31 -18
- package/src/utils/commonApi.js +4 -1
- package/src/utils/oraWrapper.js +6 -1
package/dist/scan/scanResults.js
CHANGED
|
@@ -4,6 +4,7 @@ const requestUtils = require('../../src/utils/requestUtils');
|
|
|
4
4
|
const oraFunctions = require('../utils/oraWrapper');
|
|
5
5
|
const _ = require('lodash');
|
|
6
6
|
const i18n = require('i18n');
|
|
7
|
+
const oraWrapper = require('../utils/oraWrapper');
|
|
7
8
|
const getScanId = async (config, codeArtifactId, client) => {
|
|
8
9
|
return client
|
|
9
10
|
.getScanId(config, codeArtifactId)
|
|
@@ -25,9 +26,13 @@ const pollScanResults = async (config, scanId, client) => {
|
|
|
25
26
|
console.log(err);
|
|
26
27
|
});
|
|
27
28
|
};
|
|
28
|
-
const returnScanResults = async (config, codeArtifactId, timeout, startScanSpinner) => {
|
|
29
|
+
const returnScanResults = async (config, codeArtifactId, newProject, timeout, startScanSpinner) => {
|
|
29
30
|
const client = commonApi.getHttpClient(config);
|
|
30
31
|
let scanId = await getScanId(config, codeArtifactId, client);
|
|
32
|
+
if (process.env.CODESEC_INVOCATION_ENVIRONMENT &&
|
|
33
|
+
process.env.CODESEC_INVOCATION_ENVIRONMENT.toUpperCase() === 'GITHUB') {
|
|
34
|
+
await client.createNewEvent(config, scanId, newProject);
|
|
35
|
+
}
|
|
31
36
|
let startTime = new Date();
|
|
32
37
|
let complete = false;
|
|
33
38
|
if (!_.isNil(scanId)) {
|
|
@@ -40,12 +45,16 @@ const returnScanResults = async (config, codeArtifactId, timeout, startScanSpinn
|
|
|
40
45
|
}
|
|
41
46
|
if (result.body.status === 'FAILED') {
|
|
42
47
|
complete = true;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
if (config.debug) {
|
|
49
|
+
oraFunctions.failSpinner(startScanSpinner, i18n.__('scanNotCompleted', 'https://docs.contrastsecurity.com/en/binary-package-preparation.html'));
|
|
50
|
+
}
|
|
51
|
+
if (result?.body?.errorMessage ===
|
|
46
52
|
'Unable to determine language for code artifact') {
|
|
53
|
+
console.log(result.body.errorMessage);
|
|
47
54
|
console.log('Try scanning again using --language param. ', i18n.__('scanOptionsLanguageSummary'));
|
|
48
55
|
}
|
|
56
|
+
oraWrapper.stopSpinner(startScanSpinner);
|
|
57
|
+
console.log('Contrast Scan Finished');
|
|
49
58
|
process.exit(1);
|
|
50
59
|
}
|
|
51
60
|
}
|
|
@@ -64,30 +73,21 @@ const returnScanResultsInstances = async (config, scanId) => {
|
|
|
64
73
|
try {
|
|
65
74
|
result = await client.getScanResultsInstances(config, scanId);
|
|
66
75
|
if (JSON.stringify(result.statusCode) == 200) {
|
|
67
|
-
return result.body;
|
|
76
|
+
return { body: result.body, statusCode: result.statusCode };
|
|
68
77
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
console.log(e.message.toString());
|
|
72
|
-
}
|
|
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;
|
|
78
|
+
if (JSON.stringify(result.statusCode) == 503) {
|
|
79
|
+
return { statusCode: result.statusCode };
|
|
81
80
|
}
|
|
82
81
|
}
|
|
83
82
|
catch (e) {
|
|
84
|
-
|
|
83
|
+
if (config.debug) {
|
|
84
|
+
console.log(e.message.toString());
|
|
85
|
+
}
|
|
85
86
|
}
|
|
86
87
|
};
|
|
87
88
|
module.exports = {
|
|
88
89
|
getScanId: getScanId,
|
|
89
90
|
returnScanResults: returnScanResults,
|
|
90
91
|
pollScanResults: pollScanResults,
|
|
91
|
-
returnScanResultsInstances: returnScanResultsInstances
|
|
92
|
-
returnScanProjectById: returnScanProjectById
|
|
92
|
+
returnScanResultsInstances: returnScanResultsInstances
|
|
93
93
|
};
|
package/dist/utils/commonApi.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const HttpClient = require('./../common/HTTPClient');
|
|
3
|
-
const { badRequestError, unauthenticatedError, forbiddenError, proxyError, genericError } = require('../common/errorHandling');
|
|
3
|
+
const { badRequestError, unauthenticatedError, forbiddenError, proxyError, genericError, maxAppError } = require('../common/errorHandling');
|
|
4
4
|
const handleResponseErrors = (res, api) => {
|
|
5
5
|
if (res.statusCode === 400) {
|
|
6
6
|
api === 'catalogue' ? badRequestError(true) : badRequestError(false);
|
|
@@ -14,6 +14,9 @@ const handleResponseErrors = (res, api) => {
|
|
|
14
14
|
else if (res.statusCode === 407) {
|
|
15
15
|
proxyError();
|
|
16
16
|
}
|
|
17
|
+
else if (res.statusCode === 412) {
|
|
18
|
+
maxAppError();
|
|
19
|
+
}
|
|
17
20
|
else {
|
|
18
21
|
genericError();
|
|
19
22
|
}
|
package/dist/utils/oraWrapper.js
CHANGED
|
@@ -6,6 +6,9 @@ const returnOra = text => {
|
|
|
6
6
|
const startSpinner = spinner => {
|
|
7
7
|
spinner.start();
|
|
8
8
|
};
|
|
9
|
+
const stopSpinner = spinner => {
|
|
10
|
+
spinner.stop();
|
|
11
|
+
};
|
|
9
12
|
const succeedSpinner = (spinner, text) => {
|
|
10
13
|
spinner.succeed(text);
|
|
11
14
|
};
|
|
@@ -16,5 +19,6 @@ module.exports = {
|
|
|
16
19
|
returnOra,
|
|
17
20
|
startSpinner,
|
|
18
21
|
succeedSpinner,
|
|
19
|
-
failSpinner
|
|
22
|
+
failSpinner,
|
|
23
|
+
stopSpinner
|
|
20
24
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/contrast",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Contrast Security's command line tool",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"test-int": "jest ./test-integration/",
|
|
25
25
|
"test-int-scan": "jest ./test-integration/scan",
|
|
26
26
|
"test-int-audit": "jest ./test-integration/audit",
|
|
27
|
-
"format": "prettier --write \"**/*.{ts,tsx,js,
|
|
28
|
-
"check-format": "prettier --check \"**/*.{ts,tsx,js,
|
|
27
|
+
"format": "prettier --write \"**/*.{ts,tsx,js,json,md,yml}\" .eslintrc.*",
|
|
28
|
+
"check-format": "prettier --check \"**/*.{ts,tsx,js,json,md,yml}\" .eslintrc.*",
|
|
29
29
|
"coverage-local": "nyc --reporter=text mocha './test/**/*.spec.js'",
|
|
30
30
|
"coverage": "yarn test --coverage",
|
|
31
31
|
"lint": "eslint --config .eslintrc.json . --ext .ts",
|
|
@@ -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",
|
|
@@ -73,12 +74,13 @@
|
|
|
73
74
|
"@types/i18n": "^0.13.2",
|
|
74
75
|
"@types/jest": "^27.4.1",
|
|
75
76
|
"@types/lodash": "^4.14.182",
|
|
77
|
+
"@types/node": "*",
|
|
76
78
|
"@typescript-eslint/eslint-plugin": "^5.21.0",
|
|
77
79
|
"@typescript-eslint/parser": "^5.21.0",
|
|
78
80
|
"csv-writer": "^1.6.0",
|
|
79
81
|
"eslint": "^8.14.0",
|
|
80
82
|
"eslint-config-prettier": "^8.5.0",
|
|
81
|
-
"eslint-plugin-prettier": "^4.
|
|
83
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
82
84
|
"husky": "^3.1.0",
|
|
83
85
|
"jest": "^27.5.1",
|
|
84
86
|
"jest-junit": "^13.2.0",
|
|
@@ -86,7 +88,7 @@
|
|
|
86
88
|
"npm-license-crawler": "^0.2.1",
|
|
87
89
|
"nyc": "^15.1.0",
|
|
88
90
|
"pkg": "^5.6.0",
|
|
89
|
-
"prettier": "^
|
|
91
|
+
"prettier": "^2.7.1",
|
|
90
92
|
"tmp": "^0.2.1",
|
|
91
93
|
"ts-jest": "^27.1.4",
|
|
92
94
|
"ts-node": "^10.7.0",
|
|
@@ -102,12 +104,15 @@
|
|
|
102
104
|
],
|
|
103
105
|
"prettier": {
|
|
104
106
|
"semi": false,
|
|
107
|
+
"trailingComma": "none",
|
|
108
|
+
"arrowParens": "avoid",
|
|
109
|
+
"bracketSpacing": true,
|
|
105
110
|
"singleQuote": true,
|
|
111
|
+
"bracketSameLine": true,
|
|
106
112
|
"overrides": [
|
|
107
113
|
{
|
|
108
114
|
"files": [
|
|
109
|
-
".eslintrc
|
|
110
|
-
".babelrc"
|
|
115
|
+
".eslintrc"
|
|
111
116
|
],
|
|
112
117
|
"options": {
|
|
113
118
|
"parser": "json"
|
|
@@ -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,7 +12,7 @@ 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 {
|
|
31
18
|
handleResponseErrors(res, 'catalogue')
|
|
@@ -34,12 +34,13 @@ const formatKeyName = value => {
|
|
|
34
34
|
return tempArr[0] + '/' + tempArr[1] + '@' + tempArr[versionIndex]
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
const shaveConsoleOutputUntilItFindsFirsDigraphMention =
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
mvnDependancyTreeOutput.
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
const shaveConsoleOutputUntilItFindsFirsDigraphMention =
|
|
38
|
+
mvnDependancyTreeOutput => {
|
|
39
|
+
//shaves of the console output until it reaches the first digraph
|
|
40
|
+
return mvnDependancyTreeOutput.substring(
|
|
41
|
+
mvnDependancyTreeOutput.indexOf('digraph')
|
|
42
|
+
)
|
|
43
|
+
}
|
|
43
44
|
|
|
44
45
|
const getDigraphObjInfo = editedOutput => {
|
|
45
46
|
//turns the output into an array of digraph information
|
|
@@ -211,10 +212,12 @@ const parseMvn = mvnDependancyTreeOutput => {
|
|
|
211
212
|
}
|
|
212
213
|
|
|
213
214
|
// testing purposes
|
|
214
|
-
exports.shaveConsoleOutputUntilItFindsFirsDigraphMention =
|
|
215
|
+
exports.shaveConsoleOutputUntilItFindsFirsDigraphMention =
|
|
216
|
+
shaveConsoleOutputUntilItFindsFirsDigraphMention
|
|
215
217
|
exports.getDigraphObjInfo = getDigraphObjInfo
|
|
216
218
|
exports.createDigraphObjKey = createDigraphObjKey
|
|
217
|
-
exports.turnDigraphDependanciesIntoArrOfInnerDep =
|
|
219
|
+
exports.turnDigraphDependanciesIntoArrOfInnerDep =
|
|
220
|
+
turnDigraphDependanciesIntoArrOfInnerDep
|
|
218
221
|
exports.hasVersion = hasVersion
|
|
219
222
|
exports.formatKeyName = formatKeyName
|
|
220
223
|
exports.createOuterDependanciesAndType = createOuterDependanciesAndType
|
|
@@ -32,4 +32,5 @@ const checkForMultipleIdentifiedLanguages = identifiedLanguages => {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
//For testing purposes
|
|
35
|
-
exports.checkForMultipleIdentifiedLanguages =
|
|
35
|
+
exports.checkForMultipleIdentifiedLanguages =
|
|
36
|
+
checkForMultipleIdentifiedLanguages
|
|
@@ -38,4 +38,5 @@ const checkForMultipleIdentifiedProjectFiles = identifiedLanguages => {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
//For testing purposes
|
|
41
|
-
exports.checkForMultipleIdentifiedProjectFiles =
|
|
41
|
+
exports.checkForMultipleIdentifiedProjectFiles =
|
|
42
|
+
checkForMultipleIdentifiedProjectFiles
|
|
@@ -29,4 +29,5 @@ const checkIdentifiedLanguageHasProjectFile = identifiedLanguages => {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
//For testing purposes
|
|
32
|
-
exports.checkIdentifiedLanguageHasProjectFile =
|
|
32
|
+
exports.checkIdentifiedLanguageHasProjectFile =
|
|
33
|
+
checkIdentifiedLanguageHasProjectFile
|
|
@@ -15,6 +15,13 @@ 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')
|
|
24
|
+
const { pollForSnapshotCompletition } = require('./sendSnapshot')
|
|
18
25
|
|
|
19
26
|
module.exports = exports = (err, analysis) => {
|
|
20
27
|
const { identifiedLanguageInfo } = analysis.languageAnalysis
|
|
@@ -45,17 +52,22 @@ module.exports = exports = (err, analysis) => {
|
|
|
45
52
|
return process.exit(5)
|
|
46
53
|
}
|
|
47
54
|
|
|
48
|
-
|
|
55
|
+
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'))
|
|
56
|
+
startSpinner(reportSpinner)
|
|
49
57
|
const snapshotResponse = await newSendSnapShot(analysis, catalogueAppId)
|
|
50
58
|
|
|
59
|
+
//poll for completion
|
|
60
|
+
const pollResult = await pollForSnapshotCompletition(
|
|
61
|
+
analysis.config,
|
|
62
|
+
snapshotResponse.id,
|
|
63
|
+
reportSpinner
|
|
64
|
+
)
|
|
65
|
+
succeedSpinner(reportSpinner, 'Contrast SCA analysis complete')
|
|
66
|
+
|
|
51
67
|
await vulnerabilityReport(analysis, catalogueAppId, snapshotResponse.id)
|
|
52
68
|
|
|
53
69
|
//should be moved to processAudit.ts once promises implemented
|
|
54
70
|
await auditSave(config)
|
|
55
|
-
|
|
56
|
-
console.log(
|
|
57
|
-
'\n ***************CONTRAST OSS ANALYSIS COMPLETE************** \n'
|
|
58
|
-
)
|
|
59
71
|
}
|
|
60
72
|
|
|
61
73
|
if (identifiedLanguageInfo.language === DOTNET) {
|
|
@@ -28,6 +28,79 @@ 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(filename)
|
|
58
|
+
language = RUBY
|
|
59
|
+
}
|
|
60
|
+
//
|
|
61
|
+
if (isPythonProjectFilename(filename)) {
|
|
62
|
+
deducedLanguages.push(filename)
|
|
63
|
+
language = PYTHON
|
|
64
|
+
}
|
|
65
|
+
//
|
|
66
|
+
// if (isPhpProjectFilename(filename)) {
|
|
67
|
+
// deducedLanguages.push({language: PHP, projectFilename: filename})
|
|
68
|
+
// }
|
|
69
|
+
//
|
|
70
|
+
// // Check for lock filenames...
|
|
71
|
+
// if (isDotNetLockFilename(filename)) {
|
|
72
|
+
// deducedLanguages.push({language: DOTNET, lockFilename: filename})
|
|
73
|
+
// }
|
|
74
|
+
//
|
|
75
|
+
if (isNodeLockFilename(filename)) {
|
|
76
|
+
deducedLanguages.push(filename)
|
|
77
|
+
language = NODE
|
|
78
|
+
}
|
|
79
|
+
//
|
|
80
|
+
// if (isRubyLockFilename(filename)) {
|
|
81
|
+
// deducedLanguages.push({language: RUBY, lockFilename: filename})
|
|
82
|
+
// }
|
|
83
|
+
//
|
|
84
|
+
// // this is pipfileLock rather than python lock as there can be different python locks
|
|
85
|
+
// if (isPipfileLockLockFilename(filename)) {
|
|
86
|
+
// deducedLanguages.push({language: PYTHON, lockFilename: filename})
|
|
87
|
+
// }
|
|
88
|
+
//
|
|
89
|
+
// if (isPhpLockFilename(filename)) {
|
|
90
|
+
// deducedLanguages.push({language: PHP, lockFilename: filename})
|
|
91
|
+
// }
|
|
92
|
+
//
|
|
93
|
+
// go does not have a lockfile, it should have a go.mod file containing the modules
|
|
94
|
+
if (isGoProjectFilename(filename)) {
|
|
95
|
+
deducedLanguages.push({ language: GO, projectFilename: filename })
|
|
96
|
+
language = GO
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
let identifiedLanguages = { [language]: deducedLanguages }
|
|
100
|
+
|
|
101
|
+
return identifiedLanguages
|
|
102
|
+
}
|
|
103
|
+
|
|
31
104
|
const deduceLanguage = filename => {
|
|
32
105
|
const deducedLanguages = []
|
|
33
106
|
|
|
@@ -136,9 +209,8 @@ module.exports = exports = (analysis, next) => {
|
|
|
136
209
|
|
|
137
210
|
let language = config.language
|
|
138
211
|
if (language === undefined) {
|
|
139
|
-
languageAnalysis.identifiedLanguages =
|
|
140
|
-
identifiedLanguages
|
|
141
|
-
)
|
|
212
|
+
languageAnalysis.identifiedLanguages =
|
|
213
|
+
reduceIdentifiedLanguages(identifiedLanguages)
|
|
142
214
|
} else {
|
|
143
215
|
let refinedIdentifiedLanguages = []
|
|
144
216
|
for (let x in identifiedLanguages) {
|
|
@@ -175,3 +247,4 @@ exports.isPhpProjectFilename = isPhpProjectFilename
|
|
|
175
247
|
exports.isPhpLockFilename = isPhpLockFilename
|
|
176
248
|
exports.deduceLanguage = deduceLanguage
|
|
177
249
|
exports.reduceIdentifiedLanguages = reduceIdentifiedLanguages
|
|
250
|
+
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,
|
|
@@ -8,52 +7,42 @@ import {
|
|
|
8
7
|
import { ReportSeverityModel } from './models/reportSeverityModel'
|
|
9
8
|
import { orderBy } from 'lodash'
|
|
10
9
|
import chalk from 'chalk'
|
|
11
|
-
import { ReportLibraryModel } from './models/reportLibraryModel'
|
|
12
|
-
import { findHighestSeverityCVE, findNameAndVersion } from './utils/reportUtils'
|
|
10
|
+
import { ReportCVEModel, ReportLibraryModel } from './models/reportLibraryModel'
|
|
13
11
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from '
|
|
12
|
+
findCVESeveritiesAndOrderByHighestPriority,
|
|
13
|
+
findHighestSeverityCVE,
|
|
14
|
+
findNameAndVersion,
|
|
15
|
+
severityCountAllCVEs
|
|
16
|
+
} from './utils/reportUtils'
|
|
17
|
+
import { SeverityCountModel } from './models/severityCountModel'
|
|
18
|
+
import {
|
|
19
|
+
ReportOutputBodyModel,
|
|
20
|
+
ReportOutputHeaderModel,
|
|
21
|
+
ReportOutputModel
|
|
22
|
+
} from './models/reportOutputModel'
|
|
19
23
|
|
|
20
24
|
export const createLibraryHeader = (
|
|
21
25
|
id: string,
|
|
22
26
|
numberOfVulnerableLibraries: number,
|
|
23
|
-
numberOfCves: number
|
|
24
|
-
name: string
|
|
27
|
+
numberOfCves: number
|
|
25
28
|
) => {
|
|
26
|
-
name
|
|
27
|
-
? console.log(`\n Application Name: ${name} | Application ID: ${id}`)
|
|
28
|
-
: console.log(` Application ID: ${id}`)
|
|
29
|
-
|
|
30
29
|
numberOfVulnerableLibraries === 1
|
|
31
30
|
? console.log(
|
|
32
|
-
|
|
33
|
-
` Found 1 vulnerable library containing ${numberOfCves} CVE's` +
|
|
34
|
-
'************************** '
|
|
31
|
+
` Found 1 vulnerable library containing ${numberOfCves} CVE's`
|
|
35
32
|
)
|
|
36
33
|
: console.log(
|
|
37
|
-
|
|
38
|
-
` Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVE's ` +
|
|
39
|
-
'************************** '
|
|
34
|
+
` Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVE's `
|
|
40
35
|
)
|
|
41
36
|
}
|
|
42
37
|
|
|
43
38
|
export const getReport = async (config: any, reportId: string) => {
|
|
44
39
|
const client = getHttpClient(config)
|
|
45
|
-
|
|
46
|
-
const reportSpinner = returnOra(i18n.__('auditReportWaiting'))
|
|
47
|
-
reportSpinner.indent = 1
|
|
48
|
-
startSpinner(reportSpinner)
|
|
49
40
|
return client
|
|
50
41
|
.getReportById(config, reportId)
|
|
51
42
|
.then((res: { statusCode: number; body: any }) => {
|
|
52
43
|
if (res.statusCode === 200) {
|
|
53
|
-
succeedSpinner(reportSpinner, i18n.__('auditReportSuccessMessage'))
|
|
54
44
|
return res.body
|
|
55
45
|
} else {
|
|
56
|
-
failSpinner(reportSpinner, i18n.__('auditReportFail'))
|
|
57
46
|
console.log('config-------------------')
|
|
58
47
|
console.log(config)
|
|
59
48
|
console.log('reportId----------------')
|
|
@@ -100,28 +89,121 @@ export const printFormattedOutput = (
|
|
|
100
89
|
report.reportOutputList.push(newOutputModel)
|
|
101
90
|
}
|
|
102
91
|
|
|
103
|
-
const
|
|
92
|
+
const orderedOutputListLowestFirst = orderBy(
|
|
104
93
|
report.reportOutputList,
|
|
105
|
-
reportListItem => reportListItem.compositeKey.highestSeverity.priority
|
|
94
|
+
reportListItem => reportListItem.compositeKey.highestSeverity.priority,
|
|
95
|
+
['desc']
|
|
106
96
|
)
|
|
107
97
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const highestSeverity =
|
|
112
|
-
|
|
98
|
+
let contrastHeaderNumCounter = 0
|
|
99
|
+
for (const reportModel of orderedOutputListLowestFirst) {
|
|
100
|
+
contrastHeaderNumCounter++
|
|
101
|
+
const { libraryName, libraryVersion, highestSeverity } =
|
|
102
|
+
reportModel.compositeKey
|
|
113
103
|
const numOfCVEs = reportModel.cveArray.length
|
|
114
104
|
|
|
115
|
-
const
|
|
105
|
+
const header = buildHeader(
|
|
106
|
+
highestSeverity,
|
|
107
|
+
contrastHeaderNumCounter,
|
|
108
|
+
libraryName,
|
|
109
|
+
libraryVersion,
|
|
110
|
+
numOfCVEs
|
|
111
|
+
)
|
|
116
112
|
|
|
117
|
-
|
|
113
|
+
const body = buildBody(reportModel.cveArray)
|
|
118
114
|
|
|
119
|
-
const
|
|
120
|
-
const cvePluralised = numOfCVEs > 1 ? 'CVEs' : 'CVE'
|
|
115
|
+
const reportOutputModel = new ReportOutputModel(header, body)
|
|
121
116
|
console.log(
|
|
122
|
-
|
|
117
|
+
reportOutputModel.header.vulnMessage,
|
|
118
|
+
reportOutputModel.header.introducesMessage
|
|
119
|
+
)
|
|
120
|
+
console.log(reportOutputModel.body.issueMessage)
|
|
121
|
+
console.log(reportOutputModel.body.adviceMessage)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function buildHeader(
|
|
126
|
+
highestSeverity: ReportSeverityModel,
|
|
127
|
+
contrastHeaderNum: number,
|
|
128
|
+
libraryName: string,
|
|
129
|
+
version: string,
|
|
130
|
+
numOfCVEs: number
|
|
131
|
+
) {
|
|
132
|
+
const vulnerabilityPluralised =
|
|
133
|
+
numOfCVEs > 1 ? 'Vulnerabilities' : 'Vulnerability'
|
|
134
|
+
const formattedHeaderNum = buildFormattedHeaderNum(contrastHeaderNum)
|
|
135
|
+
|
|
136
|
+
const vulnMessage = chalk
|
|
137
|
+
.hex(highestSeverity.outputColour)
|
|
138
|
+
.bold(
|
|
139
|
+
`${formattedHeaderNum} - [${highestSeverity.severity}] ${libraryName}-${version}`
|
|
123
140
|
)
|
|
124
|
-
|
|
125
|
-
|
|
141
|
+
|
|
142
|
+
const introducesMessage = chalk.bold(
|
|
143
|
+
`introduces ${numOfCVEs} ${vulnerabilityPluralised}`
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
return new ReportOutputHeaderModel(vulnMessage, introducesMessage)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function buildBody(cveArray: ReportCVEModel[]) {
|
|
150
|
+
const cveMessages: string[] = []
|
|
151
|
+
|
|
152
|
+
findCVESeveritiesAndOrderByHighestPriority(cveArray).forEach(
|
|
153
|
+
reportSeverityModel => {
|
|
154
|
+
// @ts-ignore
|
|
155
|
+
const { outputColour, severity, cveName } = reportSeverityModel
|
|
156
|
+
|
|
157
|
+
const severityShorthand = chalk
|
|
158
|
+
.hex(outputColour)
|
|
159
|
+
.bold(`[${severity.charAt(0).toUpperCase()}]`)
|
|
160
|
+
|
|
161
|
+
const builtMessage = `${severityShorthand} ${cveName}`
|
|
162
|
+
cveMessages.push(builtMessage)
|
|
163
|
+
}
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
const numAndSeverityType = getNumOfAndSeverityType(cveArray)
|
|
167
|
+
|
|
168
|
+
const issueMessage = ` ${chalk.bold(
|
|
169
|
+
'Issue'
|
|
170
|
+
)} : ${numAndSeverityType} ${cveMessages.join(', ')}.`
|
|
171
|
+
|
|
172
|
+
const adviceMessage = ` ${chalk.bold('Advice')} : ${chalk.bold(
|
|
173
|
+
'Update to latest version'
|
|
174
|
+
)}.`
|
|
175
|
+
|
|
176
|
+
return new ReportOutputBodyModel(issueMessage, adviceMessage)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function buildFormattedHeaderNum(contrastHeaderNum: number) {
|
|
180
|
+
let formattedHeaderNum
|
|
181
|
+
|
|
182
|
+
if (contrastHeaderNum < 10) {
|
|
183
|
+
formattedHeaderNum = `00${contrastHeaderNum}`
|
|
184
|
+
} else if (contrastHeaderNum >= 10 && contrastHeaderNum < 100) {
|
|
185
|
+
formattedHeaderNum = `0${contrastHeaderNum}`
|
|
186
|
+
} else if (contrastHeaderNum >= 100) {
|
|
187
|
+
formattedHeaderNum = contrastHeaderNum
|
|
126
188
|
}
|
|
189
|
+
|
|
190
|
+
return `CONTRAST-${formattedHeaderNum}`
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function getNumOfAndSeverityType(cveArray: ReportCVEModel[]) {
|
|
194
|
+
const { critical, high, medium, low, note } = severityCountAllCVEs(
|
|
195
|
+
cveArray,
|
|
196
|
+
new SeverityCountModel()
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
const criticalMessage = critical > 0 ? `${critical} Critical` : ''
|
|
200
|
+
const highMessage = high > 0 ? `${high} High` : ''
|
|
201
|
+
const mediumMessage = medium > 0 ? `${medium} Medium` : ''
|
|
202
|
+
const lowMessage = low > 0 ? `${low} Low` : ''
|
|
203
|
+
const noteMessage = note > 0 ? `${note} Note` : ''
|
|
204
|
+
|
|
205
|
+
//removes/trims whitespace to single spaces
|
|
206
|
+
return `${criticalMessage} ${highMessage} ${mediumMessage} ${lowMessage} ${noteMessage}`
|
|
207
|
+
.replace(/\s+/g, ' ')
|
|
208
|
+
.trim()
|
|
127
209
|
}
|