@contrast/contrast 1.0.9 → 1.0.12
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 +2 -2
- package/dist/audit/languageAnalysisEngine/getProjectRootFilenames.js +17 -17
- package/dist/audit/{languageAnalysisEngine/report → report}/commonReportingFunctions.js +56 -35
- package/dist/audit/report/models/reportGuidanceModel.js +6 -0
- package/dist/audit/{languageAnalysisEngine/report → report}/models/reportLibraryModel.js +0 -0
- package/dist/audit/{languageAnalysisEngine/report → report}/models/reportListModel.js +0 -0
- package/dist/audit/{languageAnalysisEngine/report → report}/models/reportOutputModel.js +1 -2
- package/dist/audit/{languageAnalysisEngine/report → report}/models/reportSeverityModel.js +0 -0
- package/dist/audit/{languageAnalysisEngine/report → report}/models/severityCountModel.js +1 -0
- package/dist/audit/{languageAnalysisEngine/report → report}/reportingFeature.js +12 -8
- package/dist/audit/{languageAnalysisEngine/report → report}/utils/reportUtils.js +3 -4
- package/dist/commands/audit/auditConfig.js +3 -3
- package/dist/commands/audit/help.js +3 -1
- 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 +20 -9
- package/dist/common/HTTPClient.js +9 -0
- package/dist/common/commonHelp.js +19 -0
- package/dist/common/errorHandling.js +2 -2
- package/dist/common/fail.js +66 -0
- package/dist/common/versionChecker.js +4 -2
- package/dist/constants/constants.js +2 -2
- package/dist/constants/locales.js +26 -11
- package/dist/constants.js +52 -5
- package/dist/index.js +5 -2
- package/dist/lambda/help.js +2 -3
- 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/javascript/index.js +3 -0
- package/dist/scaAnalysis/php/analysis.js +1 -1
- package/dist/scaAnalysis/php/index.js +12 -6
- package/dist/scaAnalysis/php/phpNewServicesMapper.js +62 -0
- 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/autoDetection.js +5 -13
- package/dist/scan/formatScanOutput.js +6 -5
- package/dist/scan/help.js +2 -3
- package/dist/scan/populateProjectIdAndProjectName.js +5 -0
- package/dist/scan/scan.js +4 -0
- package/dist/scan/scanConfig.js +4 -4
- package/dist/scan/scanResults.js +46 -3
- package/dist/telemetry/telemetry.js +137 -0
- package/dist/utils/commonApi.js +1 -1
- package/dist/utils/getConfig.js +2 -4
- package/dist/utils/parsedCLIOptions.js +3 -1
- package/dist/utils/requestUtils.js +7 -1
- package/package.json +4 -2
- package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +22 -29
- package/src/audit/{languageAnalysisEngine/report → report}/commonReportingFunctions.ts +80 -44
- package/src/audit/report/models/reportGuidanceModel.ts +5 -0
- package/src/audit/{languageAnalysisEngine/report → report}/models/reportLibraryModel.ts +0 -0
- package/src/audit/{languageAnalysisEngine/report → report}/models/reportListModel.ts +0 -0
- package/src/audit/{languageAnalysisEngine/report → report}/models/reportOutputModel.ts +1 -7
- package/src/audit/{languageAnalysisEngine/report → report}/models/reportSeverityModel.ts +0 -0
- package/src/audit/{languageAnalysisEngine/report → report}/models/severityCountModel.ts +2 -0
- package/src/audit/{languageAnalysisEngine/report → report}/reportingFeature.ts +16 -9
- package/src/audit/{languageAnalysisEngine/report → report}/utils/reportUtils.ts +4 -4
- package/src/commands/audit/auditConfig.ts +10 -3
- package/src/commands/audit/help.ts +3 -1
- 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 +27 -10
- package/src/common/HTTPClient.js +15 -0
- package/src/common/commonHelp.ts +13 -0
- package/src/common/errorHandling.ts +2 -3
- package/src/common/fail.js +75 -0
- package/src/common/versionChecker.ts +4 -4
- package/src/constants/constants.js +2 -2
- package/src/constants/locales.js +35 -13
- package/src/constants.js +56 -6
- package/src/index.ts +17 -2
- package/src/lambda/help.ts +2 -3
- package/src/scaAnalysis/common/scaParserForGoAndJava.js +41 -0
- package/src/scaAnalysis/common/treeUpload.js +21 -5
- 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/javascript/index.js +3 -0
- package/src/scaAnalysis/php/analysis.js +1 -1
- package/src/scaAnalysis/php/index.js +12 -6
- package/src/scaAnalysis/php/phpNewServicesMapper.js +77 -0
- 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/autoDetection.js +6 -13
- package/src/scan/formatScanOutput.ts +7 -5
- package/src/scan/help.js +2 -3
- package/src/scan/populateProjectIdAndProjectName.js +5 -1
- package/src/scan/scan.ts +4 -0
- package/src/scan/scanConfig.js +6 -4
- package/src/scan/scanResults.js +52 -3
- package/src/telemetry/telemetry.ts +154 -0
- package/src/utils/commonApi.js +1 -1
- package/src/utils/getConfig.ts +2 -11
- package/src/utils/parsedCLIOptions.js +14 -1
- package/src/utils/requestUtils.js +8 -1
|
@@ -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
|
};
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const i18n = require('i18n');
|
|
3
3
|
const fileFinder = require('./fileUtils');
|
|
4
4
|
const rootFile = require('../audit/languageAnalysisEngine/getProjectRootFilenames');
|
|
5
|
+
const path = require('path');
|
|
5
6
|
const autoDetectFileAndLanguage = async (configToUse) => {
|
|
6
7
|
const entries = await fileFinder.findFile();
|
|
7
8
|
if (entries.length === 1) {
|
|
@@ -23,16 +24,9 @@ const autoDetectFileAndLanguage = async (configToUse) => {
|
|
|
23
24
|
errorOnFileDetection(entries);
|
|
24
25
|
}
|
|
25
26
|
};
|
|
26
|
-
const autoDetectAuditFilesAndLanguages = async (
|
|
27
|
-
const filePath = file;
|
|
27
|
+
const autoDetectAuditFilesAndLanguages = async (filePath) => {
|
|
28
28
|
let languagesFound = [];
|
|
29
|
-
|
|
30
|
-
rootFile.getProjectRootFilenames(filePath);
|
|
31
|
-
console.log(i18n.__('searchingAuditFileDirectory', filePath));
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
console.log(i18n.__('searchingAuditFileDirectory', process.cwd()));
|
|
35
|
-
}
|
|
29
|
+
console.log(i18n.__('searchingAuditFileDirectory', filePath));
|
|
36
30
|
await fileFinder.findFilesJava(languagesFound, filePath);
|
|
37
31
|
await fileFinder.findFilesJavascript(languagesFound, filePath);
|
|
38
32
|
await fileFinder.findFilesPython(languagesFound, filePath);
|
|
@@ -40,12 +34,10 @@ const autoDetectAuditFilesAndLanguages = async (file) => {
|
|
|
40
34
|
await fileFinder.findFilesPhp(languagesFound, filePath);
|
|
41
35
|
await fileFinder.findFilesRuby(languagesFound, filePath);
|
|
42
36
|
await fileFinder.findFilesDotNet(languagesFound, filePath);
|
|
43
|
-
if (languagesFound
|
|
37
|
+
if (languagesFound) {
|
|
44
38
|
return languagesFound;
|
|
45
39
|
}
|
|
46
|
-
|
|
47
|
-
console.log('found multiple languages, please specify one using --file to run SCA audit');
|
|
48
|
-
}
|
|
40
|
+
return [];
|
|
49
41
|
};
|
|
50
42
|
const hasWhiteSpace = s => {
|
|
51
43
|
const filename = s.split('/').pop();
|
|
@@ -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) {
|
package/dist/scan/help.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const commandLineUsage = require('command-line-usage');
|
|
3
3
|
const i18n = require('i18n');
|
|
4
4
|
const constants = require('../constants');
|
|
5
|
+
const { commonHelpLinks } = require('../common/commonHelp');
|
|
5
6
|
const scanUsageGuide = commandLineUsage([
|
|
6
7
|
{
|
|
7
8
|
header: i18n.__('scanHeader')
|
|
@@ -35,9 +36,7 @@ const scanUsageGuide = commandLineUsage([
|
|
|
35
36
|
'application-name'
|
|
36
37
|
]
|
|
37
38
|
},
|
|
38
|
-
|
|
39
|
-
content: '{underline https://www.contrastsecurity.com}'
|
|
40
|
-
}
|
|
39
|
+
commonHelpLinks()
|
|
41
40
|
]);
|
|
42
41
|
module.exports = {
|
|
43
42
|
scanUsageGuide
|
|
@@ -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
|
-
const constants = require('
|
|
4
|
-
const parsedCLIOptions = require('../../src/utils/parsedCLIOptions');
|
|
3
|
+
const constants = require('../constants.js');
|
|
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,50 @@ 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
|
+
const isCI = process.env.CONTRAST_CODESEC_CI
|
|
69
|
+
? JSON.parse(process.env.CONTRAST_CODESEC_CI)
|
|
70
|
+
: false;
|
|
71
|
+
if (!isCI) {
|
|
72
|
+
const retry = await retryScanPrompt();
|
|
73
|
+
timeout = retry.timeout;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
console.log('Please try again, allowing more time');
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
66
79
|
}
|
|
67
80
|
}
|
|
68
81
|
}
|
|
69
82
|
};
|
|
83
|
+
const retryScanPrompt = async () => {
|
|
84
|
+
const rl = readLine.createInterface({
|
|
85
|
+
input: process.stdin,
|
|
86
|
+
output: process.stdout
|
|
87
|
+
});
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
requestUtils.timeOutError(30000, reject);
|
|
90
|
+
rl.question('🔁 Do you want to continue waiting on Scan? [Y/N]\n', async (input) => {
|
|
91
|
+
if (input.toLowerCase() === 'yes' || input.toLowerCase() === 'y') {
|
|
92
|
+
console.log('Continuing wait for Scan');
|
|
93
|
+
rl.close();
|
|
94
|
+
resolve({ timeout: 300 });
|
|
95
|
+
}
|
|
96
|
+
else if (input.toLowerCase() === 'no' ||
|
|
97
|
+
input.toLowerCase() === 'n') {
|
|
98
|
+
rl.close();
|
|
99
|
+
console.log('Contrast Scan Retry Cancelled: Exiting');
|
|
100
|
+
resolve(process.exit(1));
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
rl.close();
|
|
104
|
+
console.log('Invalid Input: Exiting');
|
|
105
|
+
resolve(process.exit(1));
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}).catch(e => {
|
|
109
|
+
throw e;
|
|
110
|
+
});
|
|
111
|
+
};
|
|
70
112
|
const returnScanResultsInstances = async (config, scanId) => {
|
|
71
113
|
const client = commonApi.getHttpClient(config);
|
|
72
114
|
let result;
|
|
@@ -89,5 +131,6 @@ module.exports = {
|
|
|
89
131
|
getScanId: getScanId,
|
|
90
132
|
returnScanResults: returnScanResults,
|
|
91
133
|
pollScanResults: pollScanResults,
|
|
92
|
-
returnScanResultsInstances: returnScanResultsInstances
|
|
134
|
+
returnScanResultsInstances: returnScanResultsInstances,
|
|
135
|
+
retryScanPrompt
|
|
93
136
|
};
|
|
@@ -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/commonApi.js
CHANGED
package/dist/utils/getConfig.js
CHANGED
|
@@ -5,16 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.setConfigValues = exports.localConfig = void 0;
|
|
7
7
|
const conf_1 = __importDefault(require("conf"));
|
|
8
|
+
const constants_1 = require("../constants/constants");
|
|
8
9
|
const localConfig = (name, version) => {
|
|
9
10
|
const config = new conf_1.default({
|
|
10
11
|
configName: name
|
|
11
12
|
});
|
|
12
13
|
config.set('version', version);
|
|
13
|
-
if (process.env.CONTRAST_CODSEC_DISABLE_UPDATE_MESSAGE) {
|
|
14
|
-
config.set('updateMessageHidden', JSON.parse(process.env.CONTRAST_CODSEC_DISABLE_UPDATE_MESSAGE.toLowerCase()));
|
|
15
|
-
}
|
|
16
14
|
if (!config.has('host')) {
|
|
17
|
-
config.set('host',
|
|
15
|
+
config.set('host', constants_1.CE_URL);
|
|
18
16
|
}
|
|
19
17
|
return config;
|
|
20
18
|
};
|
|
@@ -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
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/contrast",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"description": "Contrast Security's command line tool",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
"test": "jest --testPathIgnorePatterns=./test-integration/",
|
|
24
24
|
"test-int": "jest ./test-integration/",
|
|
25
25
|
"test-int-scan": "jest ./test-integration/scan",
|
|
26
|
-
"test-int-audit": "jest test-integration/audit
|
|
26
|
+
"test-int-audit": "jest test-integration/audit",
|
|
27
|
+
"test-int-audit-reports": "jest test-integration/audit/audit-language-reports.spec.js",
|
|
28
|
+
"test-int-audit-features": "jest test-integration/audit/auditFeatures/",
|
|
27
29
|
"format": "prettier --write \"**/*.{ts,tsx,js,json,md,yml}\" .eslintrc.*",
|
|
28
30
|
"check-format": "prettier --check \"**/*.{ts,tsx,js,json,md,yml}\" .eslintrc.*",
|
|
29
31
|
"coverage-local": "nyc --reporter=text mocha './test/**/*.spec.js'",
|
|
@@ -2,42 +2,35 @@ const fs = require('fs')
|
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const i18n = require('i18n')
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
let projectStats =
|
|
5
|
+
const getDirectoryFromPathGiven = file => {
|
|
6
|
+
let projectStats = getProjectStats(file)
|
|
7
|
+
|
|
8
|
+
if (projectStats.isFile()) {
|
|
9
|
+
let newPath = path.resolve(file)
|
|
10
|
+
return path.dirname(newPath)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (projectStats.isDirectory()) {
|
|
14
|
+
return file
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const getProjectStats = file => {
|
|
7
19
|
try {
|
|
8
|
-
|
|
20
|
+
//might not need this
|
|
21
|
+
if (file.endsWith('/')) {
|
|
22
|
+
file = file.slice(0, -1)
|
|
23
|
+
}
|
|
24
|
+
return fs.statSync(file)
|
|
9
25
|
} catch (err) {
|
|
10
26
|
throw new Error(
|
|
11
27
|
i18n.__('languageAnalysisProjectRootFileNameFailure', file) +
|
|
12
28
|
`${err.message}`
|
|
13
29
|
)
|
|
14
30
|
}
|
|
15
|
-
|
|
16
|
-
// Return the contents of a directory...
|
|
17
|
-
if (projectStats.isDirectory()) {
|
|
18
|
-
try {
|
|
19
|
-
return fs.readdirSync(file)
|
|
20
|
-
} catch (err) {
|
|
21
|
-
throw new Error(
|
|
22
|
-
i18n.__('languageAnalysisProjectRootFileNameReadError', file) +
|
|
23
|
-
`${err.message}`
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// If we are working with a file return it in a list as we do when we work
|
|
29
|
-
// with a directory...
|
|
30
|
-
if (projectStats.isFile()) {
|
|
31
|
-
return [path.basename(file)]
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Error out if we are working with something like a socket file or some
|
|
35
|
-
// other craziness...
|
|
36
|
-
throw new Error(
|
|
37
|
-
i18n.__('languageAnalysisProjectRootFileNameMissingError'),
|
|
38
|
-
file
|
|
39
|
-
)
|
|
40
31
|
}
|
|
32
|
+
|
|
41
33
|
module.exports = {
|
|
42
|
-
|
|
34
|
+
getProjectStats,
|
|
35
|
+
getDirectoryFromPathGiven: getDirectoryFromPathGiven
|
|
43
36
|
}
|