@contrast/contrast 1.0.10 → 1.0.11
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/README.md +1 -1
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +39 -28
- package/dist/audit/languageAnalysisEngine/report/models/reportGuidanceModel.js +6 -0
- package/dist/audit/languageAnalysisEngine/report/models/reportOutputModel.js +1 -2
- package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +1 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +11 -7
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +1 -2
- package/dist/commands/audit/auditConfig.js +3 -3
- package/dist/commands/audit/processAudit.js +4 -2
- package/dist/commands/auth/auth.js +1 -1
- package/dist/commands/config/config.js +2 -2
- package/dist/commands/scan/processScan.js +11 -4
- package/dist/commands/scan/sca/scaAnalysis.js +10 -3
- package/dist/common/HTTPClient.js +9 -0
- package/dist/common/fail.js +66 -0
- package/dist/common/versionChecker.js +1 -1
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +6 -3
- package/dist/constants.js +39 -1
- package/dist/index.js +5 -2
- package/dist/scaAnalysis/common/scaParserForGoAndJava.js +32 -0
- package/dist/scaAnalysis/common/treeUpload.js +20 -5
- package/dist/scaAnalysis/dotnet/analysis.js +15 -3
- package/dist/scaAnalysis/go/goAnalysis.js +8 -2
- package/dist/scaAnalysis/java/analysis.js +10 -6
- package/dist/scaAnalysis/java/index.js +7 -1
- package/dist/scaAnalysis/java/javaBuildDepsParser.js +19 -3
- package/dist/scaAnalysis/python/analysis.js +43 -5
- package/dist/scaAnalysis/python/index.js +7 -2
- package/dist/scaAnalysis/ruby/analysis.js +14 -4
- package/dist/scan/formatScanOutput.js +6 -5
- package/dist/scan/populateProjectIdAndProjectName.js +5 -0
- package/dist/scan/scan.js +4 -0
- package/dist/scan/scanConfig.js +3 -3
- package/dist/scan/scanResults.js +39 -3
- package/dist/telemetry/telemetry.js +137 -0
- package/dist/utils/getConfig.js +2 -2
- package/dist/utils/parsedCLIOptions.js +3 -1
- package/dist/utils/requestUtils.js +7 -1
- package/package.json +1 -1
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +57 -39
- package/src/audit/languageAnalysisEngine/report/models/reportGuidanceModel.ts +5 -0
- package/src/audit/languageAnalysisEngine/report/models/reportOutputModel.ts +1 -7
- package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +2 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +15 -8
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +2 -2
- package/src/commands/audit/auditConfig.ts +10 -3
- package/src/commands/audit/processAudit.ts +16 -2
- package/src/commands/auth/auth.js +3 -1
- package/src/commands/config/config.js +4 -2
- package/src/commands/scan/processScan.js +18 -4
- package/src/commands/scan/sca/scaAnalysis.js +11 -3
- package/src/common/HTTPClient.js +14 -0
- package/src/common/fail.js +75 -0
- package/src/common/versionChecker.ts +1 -1
- package/src/constants/constants.js +1 -1
- package/src/constants/locales.js +8 -4
- package/src/constants.js +43 -1
- package/src/index.ts +17 -2
- package/src/scaAnalysis/common/scaParserForGoAndJava.js +41 -0
- package/src/scaAnalysis/common/treeUpload.js +21 -6
- package/src/scaAnalysis/dotnet/analysis.js +21 -3
- package/src/scaAnalysis/go/goAnalysis.js +9 -2
- package/src/scaAnalysis/java/analysis.js +11 -6
- package/src/scaAnalysis/java/index.js +9 -1
- package/src/scaAnalysis/java/javaBuildDepsParser.js +25 -6
- package/src/scaAnalysis/python/analysis.js +49 -5
- package/src/scaAnalysis/python/index.js +7 -2
- package/src/scaAnalysis/ruby/analysis.js +16 -4
- package/src/scan/formatScanOutput.ts +7 -5
- package/src/scan/populateProjectIdAndProjectName.js +5 -1
- package/src/scan/scan.ts +4 -0
- package/src/scan/scanConfig.js +5 -3
- package/src/scan/scanResults.js +46 -3
- package/src/telemetry/telemetry.ts +154 -0
- package/src/utils/getConfig.ts +4 -6
- package/src/utils/parsedCLIOptions.js +14 -1
- package/src/utils/requestUtils.js +8 -1
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
const commonApi = require('../../utils/commonApi');
|
|
3
3
|
const { APP_VERSION } = require('../../constants/constants');
|
|
4
4
|
const commonSendSnapShot = async (analysis, config) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
let requestBody = {};
|
|
6
|
+
config.experimental === true
|
|
7
|
+
? (requestBody = sendToSCAServices(config, analysis))
|
|
8
|
+
: (requestBody = {
|
|
9
|
+
appID: config.applicationId,
|
|
10
|
+
cliVersion: APP_VERSION,
|
|
11
|
+
snapshot: analysis
|
|
12
|
+
});
|
|
10
13
|
const client = commonApi.getHttpClient(config);
|
|
11
14
|
return client
|
|
12
15
|
.sendSnapshot(requestBody, config)
|
|
@@ -22,6 +25,18 @@ const commonSendSnapShot = async (analysis, config) => {
|
|
|
22
25
|
throw err;
|
|
23
26
|
});
|
|
24
27
|
};
|
|
28
|
+
const sendToSCAServices = (config, analysis) => {
|
|
29
|
+
return {
|
|
30
|
+
applicationId: config.applicationId,
|
|
31
|
+
dependencyTree: analysis,
|
|
32
|
+
organizationId: config.organizationId,
|
|
33
|
+
language: config.language,
|
|
34
|
+
tool: {
|
|
35
|
+
name: 'Contrast Codesec',
|
|
36
|
+
version: APP_VERSION
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
};
|
|
25
40
|
module.exports = {
|
|
26
41
|
commonSendSnapShot
|
|
27
42
|
};
|
|
@@ -31,13 +31,25 @@ const readAndParseLockFile = lockFilePath => {
|
|
|
31
31
|
}
|
|
32
32
|
return lockFile;
|
|
33
33
|
};
|
|
34
|
+
const checkForCorrectFiles = languageFiles => {
|
|
35
|
+
if (!languageFiles.includes('packages.lock.json')) {
|
|
36
|
+
throw new Error(i18n.__('languageAnalysisHasNoLockFile', '.NET'));
|
|
37
|
+
}
|
|
38
|
+
if (!languageFiles.some(i => i.includes('.csproj'))) {
|
|
39
|
+
throw new Error(i18n.__('languageAnalysisProjectFileError', '.NET'));
|
|
40
|
+
}
|
|
41
|
+
};
|
|
34
42
|
const getDotNetDeps = (filePath, languageFiles) => {
|
|
35
|
-
|
|
36
|
-
const
|
|
43
|
+
checkForCorrectFiles(languageFiles);
|
|
44
|
+
const projectFileName = languageFiles.find(fileName => fileName.includes('.csproj'));
|
|
45
|
+
const lockFileName = languageFiles.find(fileName => fileName.includes('.json'));
|
|
46
|
+
const projectFile = readAndParseProjectFile(filePath + `/${projectFileName}`);
|
|
47
|
+
const lockFile = readAndParseLockFile(filePath + `/${lockFileName}`);
|
|
37
48
|
return { projectFile, lockFile };
|
|
38
49
|
};
|
|
39
50
|
module.exports = {
|
|
40
51
|
getDotNetDeps,
|
|
41
52
|
readAndParseProjectFile,
|
|
42
|
-
readAndParseLockFile
|
|
53
|
+
readAndParseLockFile,
|
|
54
|
+
checkForCorrectFiles
|
|
43
55
|
};
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const { createGoTSMessage } = require('../common/formatMessage');
|
|
3
|
+
const { parseDependenciesForSCAServices } = require('../common/scaParserForGoAndJava');
|
|
3
4
|
const goReadDepFile = require('./goReadDepFile');
|
|
4
5
|
const goParseDeps = require('./goParseDeps');
|
|
5
|
-
const goAnalysis =
|
|
6
|
+
const goAnalysis = config => {
|
|
6
7
|
try {
|
|
7
8
|
const rawGoDependencies = goReadDepFile.getGoDependencies(config);
|
|
8
9
|
const parsedGoDependencies = goParseDeps.parseGoDependencies(rawGoDependencies);
|
|
9
|
-
|
|
10
|
+
if (config.experimental) {
|
|
11
|
+
return parseDependenciesForSCAServices(parsedGoDependencies);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
return createGoTSMessage(parsedGoDependencies);
|
|
15
|
+
}
|
|
10
16
|
}
|
|
11
17
|
catch (e) {
|
|
12
18
|
console.log(e.message.toString());
|
|
@@ -5,17 +5,20 @@ const i18n = require('i18n');
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const MAVEN = 'maven';
|
|
7
7
|
const GRADLE = 'gradle';
|
|
8
|
-
const determineProjectTypeAndCwd = (files,
|
|
8
|
+
const determineProjectTypeAndCwd = (files, config) => {
|
|
9
9
|
const projectData = {};
|
|
10
|
+
if (files.length > 1) {
|
|
11
|
+
files = files.filter(i => config.fileName.includes(i));
|
|
12
|
+
}
|
|
10
13
|
if (files[0].includes('pom.xml')) {
|
|
11
14
|
projectData.projectType = MAVEN;
|
|
12
15
|
}
|
|
13
16
|
else if (files[0].includes('build.gradle')) {
|
|
14
17
|
projectData.projectType = GRADLE;
|
|
15
18
|
}
|
|
16
|
-
projectData.cwd = file
|
|
17
|
-
? file.replace('pom.xml', '').replace('build.gradle', '')
|
|
18
|
-
: file;
|
|
19
|
+
projectData.cwd = config.file
|
|
20
|
+
? config.file.replace('pom.xml', '').replace('build.gradle', '')
|
|
21
|
+
: config.file;
|
|
19
22
|
return projectData;
|
|
20
23
|
};
|
|
21
24
|
const buildMaven = (config, projectData, timeout) => {
|
|
@@ -86,7 +89,7 @@ const getJavaBuildDeps = (config, files) => {
|
|
|
86
89
|
projectType: undefined
|
|
87
90
|
};
|
|
88
91
|
try {
|
|
89
|
-
const projectData = determineProjectTypeAndCwd(files, config
|
|
92
|
+
const projectData = determineProjectTypeAndCwd(files, config);
|
|
90
93
|
if (projectData.projectType === MAVEN) {
|
|
91
94
|
output.mvnDependancyTreeOutput = buildMaven(config, projectData, timeout);
|
|
92
95
|
}
|
|
@@ -101,5 +104,6 @@ const getJavaBuildDeps = (config, files) => {
|
|
|
101
104
|
}
|
|
102
105
|
};
|
|
103
106
|
module.exports = {
|
|
104
|
-
getJavaBuildDeps
|
|
107
|
+
getJavaBuildDeps,
|
|
108
|
+
determineProjectTypeAndCwd
|
|
105
109
|
};
|
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
const analysis = require('./analysis');
|
|
3
3
|
const { parseBuildDeps } = require('./javaBuildDepsParser');
|
|
4
4
|
const { createJavaTSMessage } = require('../common/formatMessage');
|
|
5
|
+
const { parseDependenciesForSCAServices } = require('../common/scaParserForGoAndJava');
|
|
5
6
|
const javaAnalysis = (config, languageFiles) => {
|
|
6
7
|
languageFiles.JAVA.forEach(file => {
|
|
7
8
|
file.replace('build.gradle.kts', 'build.gradle');
|
|
8
9
|
});
|
|
9
10
|
const javaDeps = buildJavaTree(config, languageFiles.JAVA);
|
|
10
|
-
|
|
11
|
+
if (config.experimental) {
|
|
12
|
+
return parseDependenciesForSCAServices(javaDeps);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return createJavaTSMessage(javaDeps);
|
|
16
|
+
}
|
|
11
17
|
};
|
|
12
18
|
const buildJavaTree = (config, files) => {
|
|
13
19
|
const javaBuildDeps = analysis.getJavaBuildDeps(config, files);
|
|
@@ -14,13 +14,12 @@ const parseBuildDeps = (config, input) => {
|
|
|
14
14
|
const preParser = shavedOutput => {
|
|
15
15
|
let obj = [];
|
|
16
16
|
for (let dep in shavedOutput) {
|
|
17
|
+
shavedOutput[dep] = shaveDependencyType(shavedOutput[dep]);
|
|
17
18
|
obj.push(shavedOutput[dep]
|
|
18
19
|
.replace('+-', '+---')
|
|
19
20
|
.replace('[INFO]', '')
|
|
20
21
|
.replace('\\-', '\\---')
|
|
21
22
|
.replace(':jar:', ':')
|
|
22
|
-
.replace(':test', '')
|
|
23
|
-
.replace(':compile', '')
|
|
24
23
|
.replace(' +', '+')
|
|
25
24
|
.replace(' |', '|')
|
|
26
25
|
.replace(' \\', '\\')
|
|
@@ -50,6 +49,21 @@ const preParser = shavedOutput => {
|
|
|
50
49
|
}
|
|
51
50
|
return depTree;
|
|
52
51
|
};
|
|
52
|
+
const shaveDependencyType = dep => {
|
|
53
|
+
if (dep.endsWith('\r')) {
|
|
54
|
+
dep = dep.slice(0, -1);
|
|
55
|
+
}
|
|
56
|
+
if (dep.endsWith(':test')) {
|
|
57
|
+
dep = dep.slice(0, -5);
|
|
58
|
+
}
|
|
59
|
+
if (dep.endsWith(':compile')) {
|
|
60
|
+
dep = dep.slice(0, -8);
|
|
61
|
+
}
|
|
62
|
+
if (dep.endsWith(':provided')) {
|
|
63
|
+
dep = dep.slice(0, -9);
|
|
64
|
+
}
|
|
65
|
+
return dep;
|
|
66
|
+
};
|
|
53
67
|
const shaveOutput = (gradleDependencyTreeOutput, projectType) => {
|
|
54
68
|
let shavedOutput = gradleDependencyTreeOutput.split('\n');
|
|
55
69
|
if (projectType === 'maven') {
|
|
@@ -335,5 +349,7 @@ module.exports = {
|
|
|
335
349
|
computeRelationToLastElement,
|
|
336
350
|
addIndentation,
|
|
337
351
|
computeLevel,
|
|
338
|
-
computeIndentation
|
|
352
|
+
computeIndentation,
|
|
353
|
+
shaveDependencyType,
|
|
354
|
+
preParser
|
|
339
355
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const multiReplace = require('string-multiple-replace');
|
|
3
3
|
const fs = require('fs');
|
|
4
|
+
const i18n = require('i18n');
|
|
4
5
|
const readAndParseProjectFile = file => {
|
|
5
6
|
const filePath = filePathForWindows(file + '/Pipfile');
|
|
6
7
|
const pipFile = fs.readFileSync(filePath, 'utf8');
|
|
@@ -18,11 +19,45 @@ const readAndParseLockFile = file => {
|
|
|
18
19
|
delete parsedPipLock['default'];
|
|
19
20
|
return parsedPipLock;
|
|
20
21
|
};
|
|
21
|
-
const
|
|
22
|
+
const readLockFile = file => {
|
|
23
|
+
const filePath = filePathForWindows(file + '/Pipfile.lock');
|
|
24
|
+
const lockFile = fs.readFileSync(filePath, 'utf8');
|
|
25
|
+
let parsedPipLock = JSON.parse(lockFile);
|
|
26
|
+
return parsedPipLock['default'];
|
|
27
|
+
};
|
|
28
|
+
const scaPythonParser = pythonDependencies => {
|
|
29
|
+
let pythonParsedDeps = {};
|
|
30
|
+
for (let key in pythonDependencies) {
|
|
31
|
+
pythonParsedDeps[key] = {};
|
|
32
|
+
pythonParsedDeps[key].version = pythonDependencies[key].version.replace('==', '');
|
|
33
|
+
pythonParsedDeps[key].group = null;
|
|
34
|
+
pythonParsedDeps[key].name = key;
|
|
35
|
+
pythonParsedDeps[key].isProduction = true;
|
|
36
|
+
pythonParsedDeps[key].dependencies = [];
|
|
37
|
+
pythonParsedDeps[key].directDependency = true;
|
|
38
|
+
}
|
|
39
|
+
return pythonParsedDeps;
|
|
40
|
+
};
|
|
41
|
+
const checkForCorrectFiles = languageFiles => {
|
|
42
|
+
if (!languageFiles.includes('Pipfile.lock')) {
|
|
43
|
+
throw new Error(i18n.__('languageAnalysisHasNoLockFile', 'python'));
|
|
44
|
+
}
|
|
45
|
+
if (!languageFiles.includes('Pipfile')) {
|
|
46
|
+
throw new Error(i18n.__('languageAnalysisProjectFileError', 'python'));
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const getPythonDeps = (config, languageFiles) => {
|
|
22
50
|
try {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
51
|
+
if (config.experimental) {
|
|
52
|
+
let pythonLockFileContents = readLockFile(config.file);
|
|
53
|
+
return scaPythonParser(pythonLockFileContents);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
checkForCorrectFiles(languageFiles);
|
|
57
|
+
const parseProject = readAndParseProjectFile(config.file);
|
|
58
|
+
const parsePip = readAndParseLockFile(config.file);
|
|
59
|
+
return { pipfileLock: parsePip, pipfilDependanceies: parseProject };
|
|
60
|
+
}
|
|
26
61
|
}
|
|
27
62
|
catch (err) {
|
|
28
63
|
console.log(err.message.toString());
|
|
@@ -37,6 +72,9 @@ const filePathForWindows = path => {
|
|
|
37
72
|
};
|
|
38
73
|
module.exports = {
|
|
39
74
|
getPythonDeps,
|
|
75
|
+
scaPythonParser,
|
|
76
|
+
readAndParseLockFile,
|
|
40
77
|
readAndParseProjectFile,
|
|
41
|
-
|
|
78
|
+
checkForCorrectFiles,
|
|
79
|
+
readLockFile
|
|
42
80
|
};
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const { createPythonTSMessage } = require('../common/formatMessage');
|
|
3
|
-
const { getPythonDeps } = require('./analysis');
|
|
3
|
+
const { getPythonDeps, secondaryParser } = require('./analysis');
|
|
4
4
|
const pythonAnalysis = (config, languageFiles) => {
|
|
5
5
|
const pythonDeps = getPythonDeps(config, languageFiles.PYTHON);
|
|
6
|
-
|
|
6
|
+
if (config.experimental) {
|
|
7
|
+
return pythonDeps;
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
return createPythonTSMessage(pythonDeps);
|
|
11
|
+
}
|
|
7
12
|
};
|
|
8
13
|
module.exports = {
|
|
9
14
|
pythonAnalysis
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const fs = require('fs');
|
|
3
|
+
const i18n = require('i18n');
|
|
3
4
|
const readAndParseGemfile = file => {
|
|
4
5
|
const gemFile = fs.readFileSync(file + '/Gemfile', 'utf8');
|
|
5
6
|
const rubyArray = gemFile.split('\n');
|
|
@@ -188,15 +189,23 @@ const buildSourceDependencyWithVersion = (whitespaceRegx, dependencyRegEx, line,
|
|
|
188
189
|
}
|
|
189
190
|
return dependencies;
|
|
190
191
|
};
|
|
191
|
-
const getRubyDeps = config => {
|
|
192
|
+
const getRubyDeps = (config, languageFiles) => {
|
|
192
193
|
try {
|
|
194
|
+
checkForCorrectFiles(languageFiles);
|
|
193
195
|
const parsedGem = readAndParseGemfile(config.file);
|
|
194
196
|
const parsedLock = readAndParseGemLockFile(config.file);
|
|
195
197
|
return { gemfilesDependanceies: parsedGem, gemfileLock: parsedLock };
|
|
196
198
|
}
|
|
197
199
|
catch (err) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
+
throw err;
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
const checkForCorrectFiles = languageFiles => {
|
|
204
|
+
if (!languageFiles.includes('Gemfile.lock')) {
|
|
205
|
+
throw new Error(i18n.__('languageAnalysisHasNoLockFile', 'ruby'));
|
|
206
|
+
}
|
|
207
|
+
if (!languageFiles.includes('Gemfile')) {
|
|
208
|
+
throw new Error(i18n.__('languageAnalysisProjectFileError', 'ruby'));
|
|
200
209
|
}
|
|
201
210
|
};
|
|
202
211
|
const trimWhiteSpace = string => {
|
|
@@ -214,5 +223,6 @@ module.exports = {
|
|
|
214
223
|
getVersion,
|
|
215
224
|
getPatchLevel,
|
|
216
225
|
formatSourceArr,
|
|
217
|
-
getSourceArray
|
|
226
|
+
getSourceArray,
|
|
227
|
+
checkForCorrectFiles
|
|
218
228
|
};
|
|
@@ -53,12 +53,12 @@ function formatScanOutput(scanResults) {
|
|
|
53
53
|
});
|
|
54
54
|
let learnRow = [];
|
|
55
55
|
let adviceRow = [];
|
|
56
|
+
const headerColour = chalk_1.default.hex(entry.colour);
|
|
56
57
|
const headerRow = [
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
chalk_1.default.hex(entry.colour).bold(`[${entry.severity}] ${entry.ruleId}`) +
|
|
58
|
+
headerColour(`CONTRAST-${count.toString().padStart(3, '0')}`),
|
|
59
|
+
headerColour(`-`),
|
|
60
|
+
headerColour(`[${entry.severity}] `) +
|
|
61
|
+
headerColour.bold(`${entry.ruleId}`) +
|
|
62
62
|
entry.message
|
|
63
63
|
];
|
|
64
64
|
const codePath = entry.codePath?.replace(/^@/, '');
|
|
@@ -90,6 +90,7 @@ function formatScanOutput(scanResults) {
|
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
printVulnInfo(projectOverview);
|
|
93
|
+
return projectOverview;
|
|
93
94
|
}
|
|
94
95
|
exports.formatScanOutput = formatScanOutput;
|
|
95
96
|
function printVulnInfo(projectOverview) {
|
|
@@ -25,6 +25,11 @@ const createProjectId = async (config, client) => {
|
|
|
25
25
|
process.exit(1);
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
|
+
if (res.statusCode === 429) {
|
|
29
|
+
console.log(i18n.__('exceededFreeTier'));
|
|
30
|
+
process.exit(1);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
28
33
|
if (res.statusCode === 201) {
|
|
29
34
|
console.log(i18n.__('projectCreatedScan'));
|
|
30
35
|
if (config.verbose) {
|
package/dist/scan/scan.js
CHANGED
|
@@ -45,6 +45,10 @@ const sendScan = async (config) => {
|
|
|
45
45
|
oraWrapper_1.default.failSpinner(startUploadSpinner, i18n_1.default.__('uploadingScanFail'));
|
|
46
46
|
console.log(i18n_1.default.__('genericServiceError', res.statusCode));
|
|
47
47
|
}
|
|
48
|
+
if (res.statusCode === 429) {
|
|
49
|
+
console.log(i18n_1.default.__('exceededFreeTier'));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
48
52
|
if (res.statusCode === 403) {
|
|
49
53
|
console.log(i18n_1.default.__('permissionsError'));
|
|
50
54
|
process.exit(1);
|
package/dist/scan/scanConfig.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const paramHandler = require('../utils/paramsUtil/paramHandler');
|
|
3
3
|
const constants = require('../../src/constants.js');
|
|
4
|
-
const parsedCLIOptions = require('../../src/utils/parsedCLIOptions');
|
|
5
4
|
const path = require('path');
|
|
6
5
|
const { supportedLanguagesScan } = require('../constants/constants');
|
|
7
6
|
const i18n = require('i18n');
|
|
8
7
|
const { scanUsageGuide } = require('./help');
|
|
9
|
-
const
|
|
10
|
-
|
|
8
|
+
const parsedCLIOptions = require('../utils/parsedCLIOptions');
|
|
9
|
+
const getScanConfig = async (contrastConf, command, argv) => {
|
|
10
|
+
let scanParams = await parsedCLIOptions.getCommandLineArgsCustom(contrastConf, command, argv, constants.commandLineDefinitions.scanOptionDefinitions);
|
|
11
11
|
if (scanParams.help) {
|
|
12
12
|
printHelpMessage();
|
|
13
13
|
process.exit(0);
|
package/dist/scan/scanResults.js
CHANGED
|
@@ -5,10 +5,14 @@ const oraFunctions = require('../utils/oraWrapper');
|
|
|
5
5
|
const _ = require('lodash');
|
|
6
6
|
const i18n = require('i18n');
|
|
7
7
|
const oraWrapper = require('../utils/oraWrapper');
|
|
8
|
+
const readLine = require('readline');
|
|
8
9
|
const getScanId = async (config, codeArtifactId, client) => {
|
|
9
10
|
return client
|
|
10
11
|
.getScanId(config, codeArtifactId)
|
|
11
12
|
.then(res => {
|
|
13
|
+
if (res.statusCode == 429) {
|
|
14
|
+
throw new Error(i18n.__('exceededFreeTier'));
|
|
15
|
+
}
|
|
12
16
|
return res.body.id;
|
|
13
17
|
})
|
|
14
18
|
.catch(err => {
|
|
@@ -61,12 +65,43 @@ const returnScanResults = async (config, codeArtifactId, newProject, timeout, st
|
|
|
61
65
|
let endTime = new Date() - startTime;
|
|
62
66
|
if (requestUtils.millisToSeconds(endTime) > timeout) {
|
|
63
67
|
oraFunctions.failSpinner(startScanSpinner, 'Contrast Scan timed out at the specified ' + timeout + ' seconds.');
|
|
64
|
-
|
|
65
|
-
|
|
68
|
+
if (!config.isCI) {
|
|
69
|
+
const retry = await retryScanPrompt();
|
|
70
|
+
timeout = retry.timeout;
|
|
71
|
+
}
|
|
66
72
|
}
|
|
67
73
|
}
|
|
68
74
|
}
|
|
69
75
|
};
|
|
76
|
+
const retryScanPrompt = async () => {
|
|
77
|
+
const rl = readLine.createInterface({
|
|
78
|
+
input: process.stdin,
|
|
79
|
+
output: process.stdout
|
|
80
|
+
});
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
requestUtils.timeOutError(30000, reject);
|
|
83
|
+
rl.question('🔁 Do you want to continue waiting on Scan? [Y/N]\n', async (input) => {
|
|
84
|
+
if (input.toLowerCase() === 'yes' || input.toLowerCase() === 'y') {
|
|
85
|
+
console.log('Continuing wait for Scan');
|
|
86
|
+
rl.close();
|
|
87
|
+
resolve({ timeout: 300 });
|
|
88
|
+
}
|
|
89
|
+
else if (input.toLowerCase() === 'no' ||
|
|
90
|
+
input.toLowerCase() === 'n') {
|
|
91
|
+
rl.close();
|
|
92
|
+
console.log('Contrast Scan Retry Cancelled: Exiting');
|
|
93
|
+
resolve(process.exit(1));
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
rl.close();
|
|
97
|
+
console.log('Invalid Input: Exiting');
|
|
98
|
+
resolve(process.exit(1));
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}).catch(e => {
|
|
102
|
+
throw e;
|
|
103
|
+
});
|
|
104
|
+
};
|
|
70
105
|
const returnScanResultsInstances = async (config, scanId) => {
|
|
71
106
|
const client = commonApi.getHttpClient(config);
|
|
72
107
|
let result;
|
|
@@ -89,5 +124,6 @@ module.exports = {
|
|
|
89
124
|
getScanId: getScanId,
|
|
90
125
|
returnScanResults: returnScanResults,
|
|
91
126
|
pollScanResults: pollScanResults,
|
|
92
|
-
returnScanResultsInstances: returnScanResultsInstances
|
|
127
|
+
returnScanResultsInstances: returnScanResultsInstances,
|
|
128
|
+
retryScanPrompt
|
|
93
129
|
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.sha1Base64Value = exports.findParamValueFromArgs = exports.paramExists = exports.obfuscateParams = exports.sendTelemetryRequest = exports.sendTelemetryConfigAsObject = exports.sendTelemetryConfigAsConfObj = exports.TELEMETRY_CLI_TIME_TO_AUTH_EVENT = exports.TELEMETRY_CLI_COMMANDS_EVENT = void 0;
|
|
27
|
+
const commonApi_1 = require("../utils/commonApi");
|
|
28
|
+
const crypto = __importStar(require("crypto"));
|
|
29
|
+
exports.TELEMETRY_CLI_COMMANDS_EVENT = 'CLI_COMMANDS';
|
|
30
|
+
exports.TELEMETRY_CLI_TIME_TO_AUTH_EVENT = 'CLI_TIME_TO_AUTH';
|
|
31
|
+
const sendTelemetryConfigAsConfObj = async (config, command, argv, result, language) => {
|
|
32
|
+
const hostParam = '--host';
|
|
33
|
+
const hostParamAlias = '-h';
|
|
34
|
+
const orgIdParam = '--organization-id';
|
|
35
|
+
const orgIdParamAlias = '-o';
|
|
36
|
+
const authParam = '--authorization';
|
|
37
|
+
const apiKeyParam = '--api-key';
|
|
38
|
+
let configToUse;
|
|
39
|
+
if ((0, exports.paramExists)(argv, hostParam, hostParamAlias) &&
|
|
40
|
+
(0, exports.paramExists)(argv, orgIdParam, orgIdParamAlias) &&
|
|
41
|
+
(0, exports.paramExists)(argv, authParam, null) &&
|
|
42
|
+
(0, exports.paramExists)(argv, apiKeyParam, null)) {
|
|
43
|
+
configToUse = {
|
|
44
|
+
host: (0, exports.findParamValueFromArgs)(argv, hostParam, hostParamAlias),
|
|
45
|
+
organizationId: (0, exports.findParamValueFromArgs)(argv, orgIdParam, orgIdParamAlias),
|
|
46
|
+
authorization: (0, exports.findParamValueFromArgs)(argv, authParam, null),
|
|
47
|
+
apiKey: (0, exports.findParamValueFromArgs)(argv, apiKeyParam, null)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
else if (config &&
|
|
51
|
+
config.get('host') &&
|
|
52
|
+
config.get('organizationId') &&
|
|
53
|
+
config.get('authorization') &&
|
|
54
|
+
config.get('apiKey')) {
|
|
55
|
+
configToUse = {
|
|
56
|
+
host: config.get('host')?.slice(0, -1),
|
|
57
|
+
organizationId: config.get('organizationId'),
|
|
58
|
+
authorization: config.get('authorization'),
|
|
59
|
+
apiKey: config.get('apiKey')
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
return await (0, exports.sendTelemetryConfigAsObject)(configToUse, command, argv, result, language);
|
|
66
|
+
};
|
|
67
|
+
exports.sendTelemetryConfigAsConfObj = sendTelemetryConfigAsConfObj;
|
|
68
|
+
const sendTelemetryConfigAsObject = async (config, command, argv, result, language) => {
|
|
69
|
+
const obfuscatedParams = (0, exports.obfuscateParams)(argv);
|
|
70
|
+
const requestBody = {
|
|
71
|
+
event: exports.TELEMETRY_CLI_COMMANDS_EVENT,
|
|
72
|
+
details: {
|
|
73
|
+
ip_address: '',
|
|
74
|
+
account_name: '',
|
|
75
|
+
account_host: '',
|
|
76
|
+
company_domain: '',
|
|
77
|
+
command: `contrast ${command} ${obfuscatedParams}`,
|
|
78
|
+
app_id: config && config.applicationId
|
|
79
|
+
? (0, exports.sha1Base64Value)(config.applicationId)
|
|
80
|
+
: 'undefined',
|
|
81
|
+
project_id: config && config.projectId
|
|
82
|
+
? (0, exports.sha1Base64Value)(config.projectId)
|
|
83
|
+
: 'undefined',
|
|
84
|
+
language: language,
|
|
85
|
+
result: result,
|
|
86
|
+
additional_info: '',
|
|
87
|
+
timestamp: new Date().toUTCString()
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
return await (0, exports.sendTelemetryRequest)(config, requestBody);
|
|
91
|
+
};
|
|
92
|
+
exports.sendTelemetryConfigAsObject = sendTelemetryConfigAsObject;
|
|
93
|
+
const sendTelemetryRequest = async (config, requestBody) => {
|
|
94
|
+
const client = (0, commonApi_1.getHttpClient)(config);
|
|
95
|
+
return client
|
|
96
|
+
.postTelemetry(config, requestBody)
|
|
97
|
+
.then((res) => {
|
|
98
|
+
if (res.statusCode !== 200 && config.debug === true) {
|
|
99
|
+
console.log('Telemetry failed to send with status', res.statusCode);
|
|
100
|
+
}
|
|
101
|
+
return { statusCode: res.statusCode, statusMessage: res.statusMessage };
|
|
102
|
+
})
|
|
103
|
+
.catch((err) => {
|
|
104
|
+
return;
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
exports.sendTelemetryRequest = sendTelemetryRequest;
|
|
108
|
+
const obfuscateParams = (argv) => {
|
|
109
|
+
return argv
|
|
110
|
+
.join(' ')
|
|
111
|
+
.replace(/--(authorization [A-Z0-9]+)/gi, '--authorization *****')
|
|
112
|
+
.replace(/-(o [A-Z0-9-]+)/gi, '-o *****')
|
|
113
|
+
.replace(/--(organization-id [A-Z0-9-]+)/gi, '--organization-id *****')
|
|
114
|
+
.replace(/--(api-key [A-Z0-9]+)/gi, '--api-key *****');
|
|
115
|
+
};
|
|
116
|
+
exports.obfuscateParams = obfuscateParams;
|
|
117
|
+
const paramExists = (argv, param, paramAlias) => {
|
|
118
|
+
return argv.find((arg) => arg === param || arg === paramAlias);
|
|
119
|
+
};
|
|
120
|
+
exports.paramExists = paramExists;
|
|
121
|
+
const findParamValueFromArgs = (argv, param, paramAlias) => {
|
|
122
|
+
let paramAsValue;
|
|
123
|
+
argv.forEach((arg, index) => {
|
|
124
|
+
if (arg === param ||
|
|
125
|
+
(arg === paramAlias &&
|
|
126
|
+
argv[index + 1] !== undefined &&
|
|
127
|
+
argv[index + 1] !== null)) {
|
|
128
|
+
paramAsValue = argv[index + 1];
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
return paramAsValue;
|
|
132
|
+
};
|
|
133
|
+
exports.findParamValueFromArgs = findParamValueFromArgs;
|
|
134
|
+
const sha1Base64Value = (value) => {
|
|
135
|
+
return crypto.createHash('sha1').update(value).digest('base64');
|
|
136
|
+
};
|
|
137
|
+
exports.sha1Base64Value = sha1Base64Value;
|
package/dist/utils/getConfig.js
CHANGED
|
@@ -10,8 +10,8 @@ const localConfig = (name, version) => {
|
|
|
10
10
|
configName: name
|
|
11
11
|
});
|
|
12
12
|
config.set('version', version);
|
|
13
|
-
if (process.env.
|
|
14
|
-
config.set('
|
|
13
|
+
if (process.env.CONTRAST_CODSEC_CI) {
|
|
14
|
+
config.set('isCI', JSON.parse(process.env.CONTRAST_CODSEC_CI.toLowerCase()));
|
|
15
15
|
}
|
|
16
16
|
if (!config.has('host')) {
|
|
17
17
|
config.set('host', 'https://ce.contrastsecurity.com/');
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const commandLineArgs = require('command-line-args');
|
|
3
|
-
const
|
|
3
|
+
const { sendTelemetryConfigAsConfObj } = require('../telemetry/telemetry');
|
|
4
|
+
const getCommandLineArgsCustom = async (contrastConf, command, parameterList, optionDefinitions) => {
|
|
4
5
|
try {
|
|
5
6
|
return commandLineArgs(optionDefinitions, {
|
|
6
7
|
argv: parameterList,
|
|
@@ -10,6 +11,7 @@ const getCommandLineArgsCustom = (parameterList, optionDefinitions) => {
|
|
|
10
11
|
});
|
|
11
12
|
}
|
|
12
13
|
catch (e) {
|
|
14
|
+
await sendTelemetryConfigAsConfObj(contrastConf, command, parameterList, 'FAILURE', 'undefined');
|
|
13
15
|
console.log(e.message.toString());
|
|
14
16
|
process.exit(1);
|
|
15
17
|
}
|
|
@@ -11,8 +11,14 @@ const millisToSeconds = millis => {
|
|
|
11
11
|
const sleep = ms => {
|
|
12
12
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
13
13
|
};
|
|
14
|
+
const timeOutError = (ms, reject) => {
|
|
15
|
+
return setTimeout(() => {
|
|
16
|
+
reject(new Error(`No input detected after 30s`));
|
|
17
|
+
}, ms);
|
|
18
|
+
};
|
|
14
19
|
module.exports = {
|
|
15
20
|
sendRequest: sendRequest,
|
|
16
21
|
sleep: sleep,
|
|
17
|
-
millisToSeconds: millisToSeconds
|
|
22
|
+
millisToSeconds: millisToSeconds,
|
|
23
|
+
timeOutError: timeOutError
|
|
18
24
|
};
|