@contrast/contrast 1.0.9 → 1.0.10
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/getProjectRootFilenames.js +17 -17
- package/dist/commands/scan/sca/scaAnalysis.js +11 -7
- package/dist/common/errorHandling.js +2 -2
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +13 -8
- package/dist/constants.js +12 -2
- package/dist/scaAnalysis/javascript/index.js +3 -0
- package/dist/scan/autoDetection.js +5 -13
- package/dist/utils/commonApi.js +1 -1
- package/package.json +1 -1
- package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +22 -29
- package/src/commands/scan/sca/scaAnalysis.js +16 -7
- package/src/common/errorHandling.ts +2 -3
- package/src/constants/constants.js +1 -1
- package/src/constants/locales.js +18 -9
- package/src/constants.js +12 -2
- package/src/scaAnalysis/javascript/index.js +3 -0
- package/src/scan/autoDetection.js +6 -13
- package/src/utils/commonApi.js +1 -1
package/README.md
CHANGED
|
@@ -52,7 +52,7 @@ export AWS_SECRET_ACCESS_KEY=<YOUR_SECRET_ACCESS_KEY>
|
|
|
52
52
|
|
|
53
53
|
- These permissions are required to gather all required information on an AWS Lambda to use the `contrast lambda` command:
|
|
54
54
|
|
|
55
|
-
- Lambda: [GetFunction](https://docs.aws.amazon.com/lambda/latest/dg/API_GetFunction.html) | [GetLayerVersion](https://docs.aws.amazon.com/lambda/latest/dg/API_GetLayerVersion.html)
|
|
55
|
+
- Lambda: [GetFunction](https://docs.aws.amazon.com/lambda/latest/dg/API_GetFunction.html) | [GetLayerVersion](https://docs.aws.amazon.com/lambda/latest/dg/API_GetLayerVersion.html) | [ListFunctions](https://docs.aws.amazon.com/lambda/latest/dg/API_ListFunctions.html)
|
|
56
56
|
- IAM: [GetRolePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetRolePolicy.html) | [GetPolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetPolicy.html) | [GetPolicyVersion](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetPolicyVersion.html) | [ListRolePolicies](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListRolePolicies.html) | [ListAttachedRolePolicies](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAttachedRolePolicies.html)
|
|
57
57
|
|
|
58
58
|
### Start scanning
|
|
@@ -2,29 +2,29 @@
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const i18n = require('i18n');
|
|
5
|
-
const
|
|
6
|
-
let projectStats =
|
|
5
|
+
const getDirectoryFromPathGiven = file => {
|
|
6
|
+
let projectStats = getProjectStats(file);
|
|
7
|
+
if (projectStats.isFile()) {
|
|
8
|
+
let newPath = path.resolve(file);
|
|
9
|
+
return path.dirname(newPath);
|
|
10
|
+
}
|
|
11
|
+
if (projectStats.isDirectory()) {
|
|
12
|
+
return file;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const getProjectStats = file => {
|
|
7
16
|
try {
|
|
8
|
-
|
|
17
|
+
if (file.endsWith('/')) {
|
|
18
|
+
file = file.slice(0, -1);
|
|
19
|
+
}
|
|
20
|
+
return fs.statSync(file);
|
|
9
21
|
}
|
|
10
22
|
catch (err) {
|
|
11
23
|
throw new Error(i18n.__('languageAnalysisProjectRootFileNameFailure', file) +
|
|
12
24
|
`${err.message}`);
|
|
13
25
|
}
|
|
14
|
-
if (projectStats.isDirectory()) {
|
|
15
|
-
try {
|
|
16
|
-
return fs.readdirSync(file);
|
|
17
|
-
}
|
|
18
|
-
catch (err) {
|
|
19
|
-
throw new Error(i18n.__('languageAnalysisProjectRootFileNameReadError', file) +
|
|
20
|
-
`${err.message}`);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
if (projectStats.isFile()) {
|
|
24
|
-
return [path.basename(file)];
|
|
25
|
-
}
|
|
26
|
-
throw new Error(i18n.__('languageAnalysisProjectRootFileNameMissingError'), file);
|
|
27
26
|
};
|
|
28
27
|
module.exports = {
|
|
29
|
-
|
|
28
|
+
getProjectStats,
|
|
29
|
+
getDirectoryFromPathGiven: getDirectoryFromPathGiven
|
|
30
30
|
};
|
|
@@ -15,16 +15,20 @@ const i18n = require('i18n');
|
|
|
15
15
|
const { vulnerabilityReportV2 } = require('../../../audit/languageAnalysisEngine/report/reportingFeature');
|
|
16
16
|
const auditSave = require('../../../audit/save');
|
|
17
17
|
const { dotNetAnalysis } = require('../../../scaAnalysis/dotnet');
|
|
18
|
+
const rootFile = require('../../../audit/languageAnalysisEngine/getProjectRootFilenames');
|
|
19
|
+
const path = require('path');
|
|
18
20
|
const processSca = async (config) => {
|
|
19
21
|
const startTime = performance.now();
|
|
20
22
|
let filesFound;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
const projectStats = await rootFile.getProjectStats(config.file);
|
|
24
|
+
let pathWithFile = projectStats.isFile();
|
|
25
|
+
let fileName = config.file;
|
|
26
|
+
config.file = pathWithFile
|
|
27
|
+
? rootFile.getDirectoryFromPathGiven(config.file).concat('/')
|
|
28
|
+
: config.file;
|
|
29
|
+
filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config.file);
|
|
30
|
+
if (filesFound.length > 1 && pathWithFile) {
|
|
31
|
+
filesFound = filesFound.filter(i => Object.values(i)[0].includes(path.basename(fileName)));
|
|
28
32
|
}
|
|
29
33
|
let messageToSend = undefined;
|
|
30
34
|
if (filesFound.length === 1) {
|
|
@@ -48,8 +48,8 @@ const reportFailureError = () => {
|
|
|
48
48
|
};
|
|
49
49
|
exports.reportFailureError = reportFailureError;
|
|
50
50
|
const genericError = (missingCliOption) => {
|
|
51
|
-
console.log(
|
|
52
|
-
console.error(i18n_1.default.__('
|
|
51
|
+
console.log(missingCliOption);
|
|
52
|
+
console.error(i18n_1.default.__('genericErrorMessage'));
|
|
53
53
|
process.exit(1);
|
|
54
54
|
};
|
|
55
55
|
exports.genericError = genericError;
|
|
@@ -12,7 +12,7 @@ const MEDIUM = 'MEDIUM';
|
|
|
12
12
|
const HIGH = 'HIGH';
|
|
13
13
|
const CRITICAL = 'CRITICAL';
|
|
14
14
|
const APP_NAME = 'contrast';
|
|
15
|
-
const APP_VERSION = '1.0.
|
|
15
|
+
const APP_VERSION = '1.0.10';
|
|
16
16
|
const TIMEOUT = 120000;
|
|
17
17
|
const HIGH_COLOUR = '#ff9900';
|
|
18
18
|
const CRITICAL_COLOUR = '#e35858';
|
|
@@ -16,7 +16,7 @@ const en_locales = () => {
|
|
|
16
16
|
languageAnalysisFactoryFailureHeader: 'FAIL',
|
|
17
17
|
libraryAnalysisError: 'Please ensure the language parameter is set in accordance to the language specified on the project path.\nContrast CLI must be run in the same directory as the project manifest file OR the project_path parameter must be used to identify the directory containing the project manifest file.\n\nFor further information please read our usage guide, which can be accessed with the following command:\n\ncontrast-cli --help',
|
|
18
18
|
yamlMissingParametersHeader: 'Missing Parameters',
|
|
19
|
-
|
|
19
|
+
genericErrorMessage: 'An error has occur please check your command again. For more information use the --help commands.',
|
|
20
20
|
unauthenticatedErrorHeader: '401 error - Unauthenticated',
|
|
21
21
|
unauthenticatedErrorMessage: 'Please check the following keys are correct:\n--organization-id, --api-key or --authorization',
|
|
22
22
|
badRequestErrorHeader: '400 error - Bad Request',
|
|
@@ -45,7 +45,7 @@ const en_locales = () => {
|
|
|
45
45
|
languageAnalysisProjectRootFileNameMissingError: "%s isn't a file or directory",
|
|
46
46
|
languageAnalysisProjectRootFileNameFailure: 'Failed to get information about the file or directory @ %s because: ',
|
|
47
47
|
languageAnalysisFailure: ' analysis failed because: ',
|
|
48
|
-
languageAnalysisNoLanguage: 'We cannot detect a project, use
|
|
48
|
+
languageAnalysisNoLanguage: 'We cannot detect a project, use -f <path> to specify a file or folder to analyze.',
|
|
49
49
|
languageAnalysisNoLanguageHelpLine: `${chalk.bold('contrast audit --help')} for more information.`,
|
|
50
50
|
NodeAnalysisFailure: 'NODE analysis failed because: ',
|
|
51
51
|
phpAnalysisFailure: 'PHP analysis failed because: ',
|
|
@@ -97,8 +97,12 @@ const en_locales = () => {
|
|
|
97
97
|
constantsSeverity: 'Allows the user to report libraries with vulnerabilities above a chosen severity level. For example, cve_severity medium only reports libraries with vulnerabilities at medium or higher severity. Values for level are high, medium or low.',
|
|
98
98
|
constantsCount: 'The number of CVEs that must be exceeded to fail a build',
|
|
99
99
|
constantsHeader: 'CodeSec by Contrast Security',
|
|
100
|
+
configHeader2: 'Config options',
|
|
101
|
+
clearHeader: '-c, --clear',
|
|
102
|
+
clearContent: 'Removes stored credentials',
|
|
100
103
|
constantsPrerequisitesContentScanLanguages: 'Java, Javascript and .NET supported',
|
|
101
|
-
constantsContrastContent:
|
|
104
|
+
constantsContrastContent: 'Use the ‘contrast’ command for fast and accurate security analysis of your applications, APIs, serverless functions, and libraries.',
|
|
105
|
+
constantsContrastCategories: '\n Code: Java, .NET, .NET Core, JavaScript\n Serverless: AWS Lambda - Java, Python\n Libraries: Java, .NET, Node, Ruby, Python, Go, PHP\n',
|
|
102
106
|
constantsUsageGuideContentRecommendation: 'Our recommendation is that this is invoked as part of a CI pipeline so that running the cli is automated as part of your build process.',
|
|
103
107
|
constantsPrerequisitesHeader: 'Pre-requisites',
|
|
104
108
|
constantsAuthUsageHeader: 'Usage',
|
|
@@ -187,12 +191,14 @@ const en_locales = () => {
|
|
|
187
191
|
permissionsError: 'You do not have the correct permissions here. \n Contact support@contrastsecurity.com to get this fixed.',
|
|
188
192
|
scanErrorFileMessage: 'We only accept the following file types: \nJava - .jar, .war \nJavaScript - .js or .zip files',
|
|
189
193
|
helpAuthSummary: 'Authenticate Contrast using your Github or Google account',
|
|
190
|
-
|
|
191
|
-
|
|
194
|
+
helpAuditSummary: 'Searches for a suitable file in the working directory to perform a security audit of dependencies and returns the results. [Contrast audit --help (for options).]',
|
|
195
|
+
helpScanSummary: 'Searches for a .jar, .war, .js, or .zip file in the working directory, uploads files for analysis, and returns the results. [For further help/options, enter scan --help]',
|
|
196
|
+
helpLambdaSummary: 'Performs a static security scan on an AWS lambda function. lambda --help (for options)',
|
|
192
197
|
helpVersionSummary: 'Displays version of Contrast CLI',
|
|
193
198
|
helpConfigSummary: 'Displays stored credentials',
|
|
194
199
|
helpSummary: 'Displays usage guide',
|
|
195
200
|
authName: 'auth',
|
|
201
|
+
auditName: 'audit',
|
|
196
202
|
scanName: 'scan',
|
|
197
203
|
lambdaName: 'lambda',
|
|
198
204
|
versionName: 'version',
|
|
@@ -205,8 +211,7 @@ const en_locales = () => {
|
|
|
205
211
|
scanOptionsFileNameSummary: 'Path of the file you want to scan. If no file is specified, Contrast searches for a .jar, .war, .exe or .zip file in the working directory.',
|
|
206
212
|
scanOptionsVerboseSummary: ' Returns extended information to the terminal.',
|
|
207
213
|
authSuccessMessage: 'Authentication successful',
|
|
208
|
-
runAuthSuccessMessage: "Now you can use Contrast
|
|
209
|
-
"or 'contrast help' to learn more about the capabilities.",
|
|
214
|
+
runAuthSuccessMessage: "Now you can use CodeSec by Contrast \nRun: \n'contrast scan' on your file \n'contrast audit' on a file or directory,\n'contrast lambda' on an AWS function.\nor 'contrast help' to learn more about the capabilities.",
|
|
210
215
|
authWaitingMessage: 'Waiting for auth...',
|
|
211
216
|
authTimedOutMessage: 'Auth Timed out, try again',
|
|
212
217
|
zipErrorScan: 'We only support zip files for JAVASCRIPT language, please set the flag --language JAVASCRIPT',
|
|
@@ -228,7 +233,7 @@ const en_locales = () => {
|
|
|
228
233
|
lambdaPrerequisitesContent: '',
|
|
229
234
|
lambdaPrerequisitesContentLambdaLanguages: 'Supported runtimes: Java & Python',
|
|
230
235
|
lambdaPrerequisitesContentLambdaDescriptionTitle: 'AWS Requirements\n',
|
|
231
|
-
lambdaPrerequisitesContentLambdaDescription: 'Make sure you have the AWS credentials configured on your local environment. \nYou need the following AWS permissions configured on your IAM user:\n - Lambda: GetFunction, GetLayerVersion
|
|
236
|
+
lambdaPrerequisitesContentLambdaDescription: 'Make sure you have the AWS credentials configured on your local environment. \nYou need the following AWS permissions configured on your IAM user:\n - Lambda: GetFunction, GetLayerVersion, ListFunctions\n - IAM: GetRolePolicy, GetPolicy, GetPolicyVersion, ListRolePolicies, ListAttachedRolePolicies',
|
|
232
237
|
scanFileNameOption: '-f, --file',
|
|
233
238
|
lambdaFunctionNameOption: '-f, --function-name',
|
|
234
239
|
lambdaListFunctionsOption: '-l, --list-functions',
|
package/dist/constants.js
CHANGED
|
@@ -189,7 +189,7 @@ const auditOptionDefinitions = [
|
|
|
189
189
|
{
|
|
190
190
|
name: 'file',
|
|
191
191
|
alias: 'f',
|
|
192
|
-
defaultValue: process.cwd(),
|
|
192
|
+
defaultValue: process.cwd().concat('/'),
|
|
193
193
|
description: '{bold ' +
|
|
194
194
|
i18n.__('constantsOptional') +
|
|
195
195
|
'}: ' +
|
|
@@ -307,7 +307,10 @@ const auditOptionDefinitions = [
|
|
|
307
307
|
const mainUsageGuide = commandLineUsage([
|
|
308
308
|
{
|
|
309
309
|
header: i18n.__('constantsHeader'),
|
|
310
|
-
content: [
|
|
310
|
+
content: [
|
|
311
|
+
i18n.__('constantsContrastContent'),
|
|
312
|
+
i18n.__('constantsContrastCategories')
|
|
313
|
+
]
|
|
311
314
|
},
|
|
312
315
|
{
|
|
313
316
|
header: i18n.__('constantsUsage'),
|
|
@@ -319,6 +322,7 @@ const mainUsageGuide = commandLineUsage([
|
|
|
319
322
|
{ name: i18n.__('authName'), summary: i18n.__('helpAuthSummary') },
|
|
320
323
|
{ name: i18n.__('scanName'), summary: i18n.__('helpScanSummary') },
|
|
321
324
|
{ name: i18n.__('lambdaName'), summary: i18n.__('helpLambdaSummary') },
|
|
325
|
+
{ name: i18n.__('auditName'), summary: i18n.__('helpAuditSummary') },
|
|
322
326
|
{ name: i18n.__('versionName'), summary: i18n.__('helpVersionSummary') },
|
|
323
327
|
{ name: i18n.__('configName'), summary: i18n.__('helpConfigSummary') },
|
|
324
328
|
{ name: i18n.__('helpName'), summary: i18n.__('helpSummary') }
|
|
@@ -326,6 +330,12 @@ const mainUsageGuide = commandLineUsage([
|
|
|
326
330
|
},
|
|
327
331
|
{
|
|
328
332
|
content: '{underline https://developer.contrastsecurity.com/} \n For technical support head to {underline https://support.contrastsecurity.com}'
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
header: i18n.__('configHeader2'),
|
|
336
|
+
content: [
|
|
337
|
+
{ name: i18n.__('clearHeader'), summary: i18n.__('clearContent') }
|
|
338
|
+
]
|
|
329
339
|
}
|
|
330
340
|
]);
|
|
331
341
|
const mainDefinition = [{ name: 'command', defaultOption: true }];
|
|
@@ -4,6 +4,9 @@ const i18n = require('i18n');
|
|
|
4
4
|
const formatMessage = require('../common/formatMessage');
|
|
5
5
|
const jsAnalysis = async (config, languageFiles) => {
|
|
6
6
|
checkForCorrectFiles(languageFiles);
|
|
7
|
+
if (!config.file.endsWith('/')) {
|
|
8
|
+
config.file = config.file.concat('/');
|
|
9
|
+
}
|
|
7
10
|
return buildNodeTree(config, languageFiles.JAVASCRIPT);
|
|
8
11
|
};
|
|
9
12
|
const buildNodeTree = async (config, files) => {
|
|
@@ -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();
|
package/dist/utils/commonApi.js
CHANGED
package/package.json
CHANGED
|
@@ -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
|
}
|
|
@@ -24,17 +24,26 @@ const {
|
|
|
24
24
|
} = require('../../../audit/languageAnalysisEngine/report/reportingFeature')
|
|
25
25
|
const auditSave = require('../../../audit/save')
|
|
26
26
|
const { dotNetAnalysis } = require('../../../scaAnalysis/dotnet')
|
|
27
|
+
const rootFile = require('../../../audit/languageAnalysisEngine/getProjectRootFilenames')
|
|
28
|
+
const path = require('path')
|
|
27
29
|
const processSca = async config => {
|
|
28
30
|
const startTime = performance.now()
|
|
29
31
|
let filesFound
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
|
|
33
|
+
const projectStats = await rootFile.getProjectStats(config.file)
|
|
34
|
+
let pathWithFile = projectStats.isFile()
|
|
35
|
+
|
|
36
|
+
let fileName = config.file
|
|
37
|
+
config.file = pathWithFile
|
|
38
|
+
? rootFile.getDirectoryFromPathGiven(config.file).concat('/')
|
|
39
|
+
: config.file
|
|
40
|
+
|
|
41
|
+
filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config.file)
|
|
42
|
+
|
|
43
|
+
if (filesFound.length > 1 && pathWithFile) {
|
|
44
|
+
filesFound = filesFound.filter(i =>
|
|
45
|
+
Object.values(i)[0].includes(path.basename(fileName))
|
|
34
46
|
)
|
|
35
|
-
} else {
|
|
36
|
-
filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(undefined)
|
|
37
|
-
config.file = process.cwd().concat('/')
|
|
38
47
|
}
|
|
39
48
|
|
|
40
49
|
// files found looks like [ { javascript: [ Array ] } ]
|
|
@@ -39,9 +39,8 @@ const reportFailureError = () => {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
const genericError = (missingCliOption: string) => {
|
|
42
|
-
|
|
43
|
-
console.
|
|
44
|
-
console.error(i18n.__('yamlMissingParametersMessage'))
|
|
42
|
+
console.log(missingCliOption)
|
|
43
|
+
console.error(i18n.__('genericErrorMessage'))
|
|
45
44
|
process.exit(1)
|
|
46
45
|
}
|
|
47
46
|
|
package/src/constants/locales.js
CHANGED
|
@@ -20,8 +20,8 @@ const en_locales = () => {
|
|
|
20
20
|
libraryAnalysisError:
|
|
21
21
|
'Please ensure the language parameter is set in accordance to the language specified on the project path.\nContrast CLI must be run in the same directory as the project manifest file OR the project_path parameter must be used to identify the directory containing the project manifest file.\n\nFor further information please read our usage guide, which can be accessed with the following command:\n\ncontrast-cli --help',
|
|
22
22
|
yamlMissingParametersHeader: 'Missing Parameters',
|
|
23
|
-
|
|
24
|
-
'
|
|
23
|
+
genericErrorMessage:
|
|
24
|
+
'An error has occur please check your command again. For more information use the --help commands.',
|
|
25
25
|
unauthenticatedErrorHeader: '401 error - Unauthenticated',
|
|
26
26
|
unauthenticatedErrorMessage:
|
|
27
27
|
'Please check the following keys are correct:\n--organization-id, --api-key or --authorization',
|
|
@@ -67,7 +67,7 @@ const en_locales = () => {
|
|
|
67
67
|
'Failed to get information about the file or directory @ %s because: ',
|
|
68
68
|
languageAnalysisFailure: ' analysis failed because: ',
|
|
69
69
|
languageAnalysisNoLanguage:
|
|
70
|
-
'We cannot detect a project, use
|
|
70
|
+
'We cannot detect a project, use -f <path> to specify a file or folder to analyze.',
|
|
71
71
|
languageAnalysisNoLanguageHelpLine: `${chalk.bold(
|
|
72
72
|
'contrast audit --help'
|
|
73
73
|
)} for more information.`,
|
|
@@ -148,10 +148,15 @@ const en_locales = () => {
|
|
|
148
148
|
'Allows the user to report libraries with vulnerabilities above a chosen severity level. For example, cve_severity medium only reports libraries with vulnerabilities at medium or higher severity. Values for level are high, medium or low.',
|
|
149
149
|
constantsCount: 'The number of CVEs that must be exceeded to fail a build',
|
|
150
150
|
constantsHeader: 'CodeSec by Contrast Security',
|
|
151
|
+
configHeader2: 'Config options',
|
|
152
|
+
clearHeader: '-c, --clear',
|
|
153
|
+
clearContent: 'Removes stored credentials',
|
|
151
154
|
constantsPrerequisitesContentScanLanguages:
|
|
152
155
|
'Java, Javascript and .NET supported',
|
|
153
156
|
constantsContrastContent:
|
|
154
|
-
|
|
157
|
+
'Use the ‘contrast’ command for fast and accurate security analysis of your applications, APIs, serverless functions, and libraries.',
|
|
158
|
+
constantsContrastCategories:
|
|
159
|
+
'\n Code: Java, .NET, .NET Core, JavaScript\n Serverless: AWS Lambda - Java, Python\n Libraries: Java, .NET, Node, Ruby, Python, Go, PHP\n',
|
|
155
160
|
constantsUsageGuideContentRecommendation:
|
|
156
161
|
'Our recommendation is that this is invoked as part of a CI pipeline so that running the cli is automated as part of your build process.',
|
|
157
162
|
constantsPrerequisitesHeader: 'Pre-requisites',
|
|
@@ -282,12 +287,17 @@ const en_locales = () => {
|
|
|
282
287
|
'We only accept the following file types: \nJava - .jar, .war \nJavaScript - .js or .zip files',
|
|
283
288
|
helpAuthSummary:
|
|
284
289
|
'Authenticate Contrast using your Github or Google account',
|
|
285
|
-
|
|
286
|
-
|
|
290
|
+
helpAuditSummary:
|
|
291
|
+
'Searches for a suitable file in the working directory to perform a security audit of dependencies and returns the results. [Contrast audit --help (for options).]',
|
|
292
|
+
helpScanSummary:
|
|
293
|
+
'Searches for a .jar, .war, .js, or .zip file in the working directory, uploads files for analysis, and returns the results. [For further help/options, enter scan --help]',
|
|
294
|
+
helpLambdaSummary:
|
|
295
|
+
'Performs a static security scan on an AWS lambda function. lambda --help (for options)',
|
|
287
296
|
helpVersionSummary: 'Displays version of Contrast CLI',
|
|
288
297
|
helpConfigSummary: 'Displays stored credentials',
|
|
289
298
|
helpSummary: 'Displays usage guide',
|
|
290
299
|
authName: 'auth',
|
|
300
|
+
auditName: 'audit',
|
|
291
301
|
scanName: 'scan',
|
|
292
302
|
lambdaName: 'lambda',
|
|
293
303
|
versionName: 'version',
|
|
@@ -305,8 +315,7 @@ const en_locales = () => {
|
|
|
305
315
|
scanOptionsVerboseSummary: ' Returns extended information to the terminal.',
|
|
306
316
|
authSuccessMessage: 'Authentication successful',
|
|
307
317
|
runAuthSuccessMessage:
|
|
308
|
-
"Now you can use Contrast
|
|
309
|
-
"or 'contrast help' to learn more about the capabilities.",
|
|
318
|
+
"Now you can use CodeSec by Contrast \nRun: \n'contrast scan' on your file \n'contrast audit' on a file or directory,\n'contrast lambda' on an AWS function.\nor 'contrast help' to learn more about the capabilities.",
|
|
310
319
|
authWaitingMessage: 'Waiting for auth...',
|
|
311
320
|
authTimedOutMessage: 'Auth Timed out, try again',
|
|
312
321
|
zipErrorScan:
|
|
@@ -334,7 +343,7 @@ const en_locales = () => {
|
|
|
334
343
|
'Supported runtimes: Java & Python',
|
|
335
344
|
lambdaPrerequisitesContentLambdaDescriptionTitle: 'AWS Requirements\n',
|
|
336
345
|
lambdaPrerequisitesContentLambdaDescription:
|
|
337
|
-
'Make sure you have the AWS credentials configured on your local environment. \nYou need the following AWS permissions configured on your IAM user:\n - Lambda: GetFunction, GetLayerVersion
|
|
346
|
+
'Make sure you have the AWS credentials configured on your local environment. \nYou need the following AWS permissions configured on your IAM user:\n - Lambda: GetFunction, GetLayerVersion, ListFunctions\n - IAM: GetRolePolicy, GetPolicy, GetPolicyVersion, ListRolePolicies, ListAttachedRolePolicies',
|
|
338
347
|
scanFileNameOption: '-f, --file',
|
|
339
348
|
lambdaFunctionNameOption: '-f, --function-name',
|
|
340
349
|
lambdaListFunctionsOption: '-l, --list-functions',
|
package/src/constants.js
CHANGED
|
@@ -213,7 +213,7 @@ const auditOptionDefinitions = [
|
|
|
213
213
|
{
|
|
214
214
|
name: 'file',
|
|
215
215
|
alias: 'f',
|
|
216
|
-
defaultValue: process.cwd(),
|
|
216
|
+
defaultValue: process.cwd().concat('/'),
|
|
217
217
|
description:
|
|
218
218
|
'{bold ' +
|
|
219
219
|
i18n.__('constantsOptional') +
|
|
@@ -347,7 +347,10 @@ const auditOptionDefinitions = [
|
|
|
347
347
|
const mainUsageGuide = commandLineUsage([
|
|
348
348
|
{
|
|
349
349
|
header: i18n.__('constantsHeader'),
|
|
350
|
-
content: [
|
|
350
|
+
content: [
|
|
351
|
+
i18n.__('constantsContrastContent'),
|
|
352
|
+
i18n.__('constantsContrastCategories')
|
|
353
|
+
]
|
|
351
354
|
},
|
|
352
355
|
{
|
|
353
356
|
header: i18n.__('constantsUsage'),
|
|
@@ -359,6 +362,7 @@ const mainUsageGuide = commandLineUsage([
|
|
|
359
362
|
{ name: i18n.__('authName'), summary: i18n.__('helpAuthSummary') },
|
|
360
363
|
{ name: i18n.__('scanName'), summary: i18n.__('helpScanSummary') },
|
|
361
364
|
{ name: i18n.__('lambdaName'), summary: i18n.__('helpLambdaSummary') },
|
|
365
|
+
{ name: i18n.__('auditName'), summary: i18n.__('helpAuditSummary') },
|
|
362
366
|
{ name: i18n.__('versionName'), summary: i18n.__('helpVersionSummary') },
|
|
363
367
|
{ name: i18n.__('configName'), summary: i18n.__('helpConfigSummary') },
|
|
364
368
|
{ name: i18n.__('helpName'), summary: i18n.__('helpSummary') }
|
|
@@ -367,6 +371,12 @@ const mainUsageGuide = commandLineUsage([
|
|
|
367
371
|
{
|
|
368
372
|
content:
|
|
369
373
|
'{underline https://developer.contrastsecurity.com/} \n For technical support head to {underline https://support.contrastsecurity.com}'
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
header: i18n.__('configHeader2'),
|
|
377
|
+
content: [
|
|
378
|
+
{ name: i18n.__('clearHeader'), summary: i18n.__('clearContent') }
|
|
379
|
+
]
|
|
370
380
|
}
|
|
371
381
|
])
|
|
372
382
|
|
|
@@ -5,6 +5,9 @@ const formatMessage = require('../common/formatMessage')
|
|
|
5
5
|
const jsAnalysis = async (config, languageFiles) => {
|
|
6
6
|
checkForCorrectFiles(languageFiles)
|
|
7
7
|
|
|
8
|
+
if (!config.file.endsWith('/')) {
|
|
9
|
+
config.file = config.file.concat('/')
|
|
10
|
+
}
|
|
8
11
|
return buildNodeTree(config, languageFiles.JAVASCRIPT)
|
|
9
12
|
}
|
|
10
13
|
const buildNodeTree = async (config, files) => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const i18n = require('i18n')
|
|
2
2
|
const fileFinder = require('./fileUtils')
|
|
3
3
|
const rootFile = require('../audit/languageAnalysisEngine/getProjectRootFilenames')
|
|
4
|
+
const path = require('path')
|
|
4
5
|
|
|
5
6
|
const autoDetectFileAndLanguage = async configToUse => {
|
|
6
7
|
const entries = await fileFinder.findFile()
|
|
@@ -27,16 +28,10 @@ const autoDetectFileAndLanguage = async configToUse => {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
const autoDetectAuditFilesAndLanguages = async
|
|
31
|
-
const filePath = file
|
|
31
|
+
const autoDetectAuditFilesAndLanguages = async filePath => {
|
|
32
32
|
let languagesFound = []
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
rootFile.getProjectRootFilenames(filePath)
|
|
36
|
-
console.log(i18n.__('searchingAuditFileDirectory', filePath))
|
|
37
|
-
} else {
|
|
38
|
-
console.log(i18n.__('searchingAuditFileDirectory', process.cwd()))
|
|
39
|
-
}
|
|
34
|
+
console.log(i18n.__('searchingAuditFileDirectory', filePath))
|
|
40
35
|
|
|
41
36
|
await fileFinder.findFilesJava(languagesFound, filePath)
|
|
42
37
|
await fileFinder.findFilesJavascript(languagesFound, filePath)
|
|
@@ -46,13 +41,11 @@ const autoDetectAuditFilesAndLanguages = async file => {
|
|
|
46
41
|
await fileFinder.findFilesRuby(languagesFound, filePath)
|
|
47
42
|
await fileFinder.findFilesDotNet(languagesFound, filePath)
|
|
48
43
|
|
|
49
|
-
if (languagesFound
|
|
44
|
+
if (languagesFound) {
|
|
50
45
|
return languagesFound
|
|
51
|
-
} else {
|
|
52
|
-
console.log(
|
|
53
|
-
'found multiple languages, please specify one using --file to run SCA audit'
|
|
54
|
-
)
|
|
55
46
|
}
|
|
47
|
+
|
|
48
|
+
return []
|
|
56
49
|
}
|
|
57
50
|
|
|
58
51
|
const hasWhiteSpace = s => {
|