@contrast/contrast 1.0.16 → 1.0.18

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.
Files changed (61) hide show
  1. package/dist/audit/catalogueApplication/catalogueApplication.js +1 -1
  2. package/dist/cliConstants.js +91 -109
  3. package/dist/commands/audit/auditConfig.js +10 -12
  4. package/dist/commands/audit/auditController.js +12 -16
  5. package/dist/commands/audit/help.js +32 -26
  6. package/dist/commands/audit/processAudit.js +16 -22
  7. package/dist/commands/audit/saveFile.js +3 -9
  8. package/dist/commands/scan/processScan.js +5 -7
  9. package/dist/commands/scan/sca/scaAnalysis.js +105 -88
  10. package/dist/common/HTTPClient.js +1 -1
  11. package/dist/common/commonHelp.js +35 -17
  12. package/dist/common/errorHandling.js +38 -57
  13. package/dist/common/versionChecker.js +24 -27
  14. package/dist/constants/constants.js +1 -1
  15. package/dist/constants/locales.js +20 -91
  16. package/dist/lambda/help.js +2 -1
  17. package/dist/lambda/lambda.js +2 -7
  18. package/dist/scaAnalysis/java/analysis.js +40 -5
  19. package/dist/scaAnalysis/java/index.js +14 -2
  20. package/dist/scan/autoDetection.js +26 -3
  21. package/dist/scan/fileUtils.js +24 -1
  22. package/dist/scan/help.js +11 -4
  23. package/dist/scan/saveResults.js +1 -1
  24. package/dist/utils/commonApi.js +16 -1
  25. package/dist/utils/generalAPI.js +1 -2
  26. package/dist/utils/paramsUtil/configStoreParams.js +12 -1
  27. package/dist/utils/paramsUtil/paramHandler.js +7 -1
  28. package/dist/utils/saveFile.js +2 -1
  29. package/package.json +2 -1
  30. package/src/audit/catalogueApplication/catalogueApplication.js +1 -1
  31. package/src/cliConstants.js +96 -116
  32. package/src/commands/audit/auditConfig.js +19 -0
  33. package/src/commands/audit/{auditController.ts → auditController.js} +17 -12
  34. package/src/commands/audit/{help.ts → help.js} +19 -7
  35. package/src/commands/audit/processAudit.js +37 -0
  36. package/src/commands/audit/{saveFile.ts → saveFile.js} +2 -2
  37. package/src/commands/scan/processScan.js +4 -10
  38. package/src/commands/scan/sca/scaAnalysis.js +135 -115
  39. package/src/common/HTTPClient.js +1 -1
  40. package/src/common/commonHelp.js +43 -0
  41. package/src/common/{errorHandling.ts → errorHandling.js} +25 -32
  42. package/src/common/{versionChecker.ts → versionChecker.js} +15 -10
  43. package/src/constants/constants.js +1 -1
  44. package/src/constants/locales.js +23 -129
  45. package/src/lambda/help.ts +2 -1
  46. package/src/lambda/lambda.ts +2 -10
  47. package/src/scaAnalysis/java/analysis.js +43 -10
  48. package/src/scaAnalysis/java/index.js +19 -2
  49. package/src/scan/autoDetection.js +34 -3
  50. package/src/scan/fileUtils.js +29 -1
  51. package/src/scan/help.js +12 -4
  52. package/src/scan/saveResults.js +1 -1
  53. package/src/utils/commonApi.js +19 -1
  54. package/src/utils/generalAPI.js +1 -2
  55. package/src/utils/getConfig.ts +1 -0
  56. package/src/utils/paramsUtil/configStoreParams.js +14 -1
  57. package/src/utils/paramsUtil/paramHandler.js +9 -1
  58. package/src/utils/saveFile.js +2 -1
  59. package/src/commands/audit/auditConfig.ts +0 -21
  60. package/src/commands/audit/processAudit.ts +0 -40
  61. package/src/common/commonHelp.ts +0 -13
@@ -3,19 +3,11 @@ const { lambda } = require('./lambda');
3
3
  const chalk = require('chalk');
4
4
  const en_locales = () => {
5
5
  return {
6
- successHeader: 'SUCCESS',
7
- snapshotSuccessMessage: 'Please go to the Contrast UI to view your dependency tree.',
8
6
  snapshotFailureHeader: 'FAIL',
9
7
  snapshotFailureMessage: 'Library analysis failed',
10
- snapshotHostMessage: "No host supplied. Using default host 'app.contrastsecurity.com'. Please ensure this is correct.",
11
- vulnerabilitiesSuccessMessage: 'Vulnerability data successfully retrieved',
12
8
  vulnerabilitiesFailureMessage: 'Unable to retrieve library vulnerabilities',
13
- catchErrorMessage: 'Contrast UI error: ',
14
9
  dependenciesNote: 'Please Note: We currently only support projects with one .csproj AND *.package.lock.json',
15
- languageAnalysisFailureMessage: 'SCA audit Failure',
16
- languageAnalysisFactoryFailureHeader: 'FAIL',
17
10
  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
- yamlMissingParametersHeader: 'Missing Parameters',
19
11
  genericErrorMessage: 'An error has occur please check your command again. For more information use the --help commands.',
20
12
  unauthenticatedErrorHeader: '401 error - Unauthenticated',
21
13
  unauthenticatedErrorMessage: 'Please check the following keys are correct:\n--organization-id, --api-key or --authorization',
@@ -26,87 +18,47 @@ const en_locales = () => {
26
18
  forbiddenRequestErrorMessage: 'You do not have permission to access this server.',
27
19
  proxyErrorHeader: '407 error - Proxy Authentication Required',
28
20
  proxyErrorMessage: 'Please provide valid authentication credentials for the proxy server.',
29
- catalogueSuccessCommand: 'Application Created',
30
- dotnetAnalysisFailure: '.NET analysis failed because: ',
31
- dotnetReadLockfile: 'Failed to read the lock file @ %s because: ',
32
- dotnetParseLockfile: "Failed to parse .NET lock file @ '%s' because: ",
33
- dotnetParseProjectFile: "Failed to parse MSBuild project file @ '%s' because: ",
34
- dotnetReadProjectFile: 'Failed to read the project file @ "%s" because: ',
35
- javaAnalysisError: 'JAVA analysis failed because: ',
36
21
  javaParseProjectFile: 'Failed to parse mvn output because: ',
37
- languageAnalysisMultipleLanguages1: 'Identified multiple languages for the project\n',
38
- languageAnalysisMultipleLanguages2: 'Please specify which project file you would like analyzed with the %s CLI option.',
39
- languageAnalysisProjectFiles: "Identified project language as '%s' but found multiple project files: %s. Please specify which project file you would like analyzed with the %s CLI option.",
40
22
  languageAnalysisHasNoLockFile: "Identified project language as '%s' but no project lock file was found.",
41
23
  languageAnalysisHasNoPackageJsonFile: 'Identified project language as javascript but no package.json file was found.',
42
24
  languageAnalysisHasMultipleLockFiles: "Identified project language as '%s' but multiple project lock files were found.",
43
25
  languageAnalysisProjectFileError: "Identified project language as '%s' but no project file was found.",
44
- languageAnalysisProjectRootFileNameReadError: 'Failed to read the contents of the directory @ %s because: ',
45
- languageAnalysisProjectRootFileNameMissingError: "%s isn't a file or directory",
46
26
  languageAnalysisProjectRootFileNameFailure: 'Failed to get information about the file or directory @ %s because: ',
47
- languageAnalysisFailure: ' analysis failed because: ',
48
27
  languageAnalysisNoLanguage: 'We cannot detect a project, use -f <path> to specify a file or folder to analyze.',
49
28
  languageAnalysisNoLanguageHelpLine: `${chalk.bold('contrast audit --help')} for more information.`,
50
- NodeAnalysisFailure: 'NODE analysis failed because: ',
51
- phpAnalysisFailure: 'PHP analysis failed because: ',
52
29
  NodeParseNPM: 'Failed to parse NODE package-lock.json file because: ',
53
30
  phpParseComposerLock: "Failed to parse PHP composer.lock file @ '%s' because: ",
54
- NodeReadNpmError: 'Failed to read the package-lock.json file @ "%s" because: ',
55
- phpReadError: 'Failed to read the composer.lock file @ "%s" because: ',
56
31
  NodeParseYarn: 'Failed to parse yarn.lock version %s because: ',
57
32
  NodeParseYarn2: "Failed to parse Node yarn.lock version 2 @ '%s' because: ",
58
- nodeReadProjectFileError: 'Failed to read the NODE project file @ "%s" because: ',
59
- phpReadProjectFileError: 'Failed to read the PHP project file @ "%s" because: ',
60
33
  nodeReadYarnLockFileError: 'Failed to read the yarn.lock file @ "%s" because: ',
61
- pythonAnalysisEngineError: 'Python analysis failed because: ',
62
- pythonAnalysisEnginePipError: "Failed to parse python Pipfile.lock file @ '%s' because: ",
63
- pythonAnalysisParseProjectFileError: 'Failed to parse python output "%s" because: ',
64
- pythonAnalysisReadPipFileError: 'Failed to read the python Pipfile.lock file @ "%s" because: ',
65
- pythonAnalysisReadPythonProjectFileError: 'Failed to read the python pipfile @ "%s" because: ',
66
- rubyAnalysisEngineError: 'Ruby analysis failed because: ',
67
- rubyAnalysisEngineParsedGemFileError: 'Failed to parse ruby output "%s" because: ',
68
- rubyAnalysisEngineParsedGemLockFileError: 'Failed to parse ruby Gemfile.lock output because: ',
69
- rubyAnalysisEngineReadGemFileError: 'Failed to read the ruby project file @ "%s" because: ',
70
- rubyAnalysisEngineReadGemLockFileError: 'Failed to read the ruby Gemfile.lock @ "%s" because: ',
71
34
  constantsOptional: '(optional)',
72
- constantsOptionalForCatalogue: '(optional for catalogue)',
73
35
  constantsRequired: '(required)',
74
- constantsRequiredCatalogue: '(required for catalogue)',
36
+ constantsRequiredEnterprise: '(required for Contrast Enterprise)',
75
37
  constantsApiKey: 'An agent API key as provided by Contrast UI',
76
- constantsAuthorization: 'Authorization credentials as provided by Contrast UI',
77
- constantsOrganizationId: 'The ID of your organization',
78
- constantsApplicationId: 'The ID of the application cataloged by Contrast UI',
79
- constantsHostId: 'Provide the name of the host and optionally the port expressed as "<host>:<port>".',
80
- constantsApplicationName: 'The name of the application cataloged by Contrast UI',
81
- constantsCatalogueApplication: 'Provide this if you want to catalogue an application',
38
+ constantsAuthorization: 'An authorization header as provided by Contrast UI',
39
+ constantsOrganizationId: 'The ID of your organization as provided by Contrast UI',
40
+ constantsApplicationId: 'The ID of the application as provided by Contrast UI',
41
+ constantsHostId: 'host name e.g. https://app.contrastsecurity.com',
42
+ constantsApplicationName: 'The name of the application as provided by Contrast UI',
82
43
  failOptionErrorMessage: ' FAIL - CVEs have been detected that match at least the cve_severity option specified.',
83
44
  failOptionMessage: ' Use with contrast scan or contrast audit. Detects failures based on the severity level specified with the --severity command. For example, "contrast scan --fail --severity high". Returns all failures if no severity level is specified.',
84
- constantsLanguage: 'Valid values are JAVA, DOTNET, NODE, PYTHON and RUBY. If there are multiple project configuration files in the project_path, language is also required. Also, provide this when cataloguing an application',
85
45
  constantsFilePath: `Specify a directory or the file where dependencies are declared. (By default, CodeSec will search for project files in the current directory.)`,
86
- constantsSilent: 'Silences JSON output.',
87
- constantsAppGroups: 'Assign your application to one or more pre-existing groups when using the catalogue command. Group lists should be comma separated.',
88
- constantsVersion: 'Displays CLI Version you are currently on.',
89
- constantsProxyServer: 'Allows for connection via a proxy server. If authentication is required please provide the username and password with the protocol, host and port. For instance: "http://username:password@<host>:<port>".',
90
- constantsHelp: 'Display this usage guide.',
46
+ constantsAppGroups: 'Assign your application to one or more pre-existing groups when on boarding an application. Group lists should be comma separated.',
47
+ constantsProxyServer: 'Allows for connection via a proxy server. If authentication is required please provide the username and password with the protocol, host and port. For instance: "https://username:password@<host>:<port>".',
91
48
  constantsGradleMultiProject: 'Specify the sub project within your gradle application.',
92
- constantsScan: 'Upload java binaries to the static scan service',
93
- constantsDoNotWaitForScan: 'Do not wait for the result of the scan',
49
+ constantsDoNotWaitForScan: 'Fire and forget. Do not wait for the result of the scan.',
94
50
  constantsProjectName: 'Contrast project name. If not specified, Contrast uses contrast.settings to identify the project or creates a project.',
95
51
  constantsProjectId: 'The ID associated with a scan project. Replace <ProjectID> with the ID for the scan project. To find the ID, select a scan project in Contrast and locate the last number in the URL.',
96
- constantsReport: 'Display vulnerability information for this application',
97
- constantsFail: 'Set the process to fail if this option is set in combination with --cve_severity.',
98
52
  failThresholdOptionErrorMessage: 'More than 0 vulnerabilities found',
99
53
  failSeverityOptionErrorMessage: ' FAIL - Results detected vulnerabilities over accepted severity level',
100
54
  constantsSeverity: 'Use with "contrast scan --fail --severity high" or "contrast audit --fail --severity high". Set the severity level to detect vulnerabilities or dependencies. Severity levels are critical, high, medium, low or note.',
101
- constantsCount: 'The number of CVEs that must be exceeded to fail a build',
102
- constantsHeader: 'CodeSec by Contrast Security',
55
+ constantsHeader: 'Contrast CLI',
103
56
  configHeader2: 'Config options',
104
57
  clearHeader: '-c, --clear',
105
58
  clearContent: 'Removes stored credentials',
106
59
  constantsPrerequisitesContentScanLanguages: 'Java, Javascript and .NET supported',
107
60
  constantsContrastContent: 'Use the ‘contrast’ command for fast and accurate security analysis of your applications, APIs, serverless functions, and libraries.',
108
61
  constantsContrastCategories: '\n Code: Java, .NET, .NET Core, JavaScript\n Serverless: AWS Lambda - Java, Python\n Libraries: Java, .NET, Node, Ruby, Python, Go, PHP\n',
109
- 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.',
110
62
  constantsPrerequisitesHeader: 'Pre-requisites',
111
63
  constantsAuthUsageHeader: 'Usage',
112
64
  constantsAuthUsageContents: 'contrast auth',
@@ -120,38 +72,26 @@ const en_locales = () => {
120
72
  constantsUsageCommandExample: 'contrast [command] [options]',
121
73
  constantsUsageCommandInfo: 'The file argument is optional. If no file is given, Contrast will search for a .jar, .war, .exe or .zip file in the working directory.\n',
122
74
  constantsUsageCommandInfo24Hours: 'Submitted files are encrypted during upload and deleted in 24 hours.',
123
- constantsAnd: 'AND',
124
- constantsJava: 'AND Maven build platform, including the dependency plugin. For a Gradle project, use build.gradle. A gradle-wrapper.properties file is also required. Kotlin is also supported requiring a build.gradle.kts file.',
125
- constantsJavaNote: 'Note: Running "mvn dependency:tree" or "./gradlew dependencies" in the project directory locally must be successful.',
126
- constantsJavaNoteGradle: 'We currently support v4.8 and upwards on Gradle projects',
127
- constantsDotNet: 'MSBuild 15.0 or greater and have a packages.lock.json file are supported.',
128
- constantsDotNetNote: 'Please Note: If the packages.lock.json file is not in place it can be generated by setting RestorePackagesWithLockFile to true within each *.csproj and running dotnet build',
129
- constantsNode: '%s AND a lock file either %s or %s',
130
- constantsRuby: 'gemfile AND gemfile.lock',
131
- constantsPython: 'pipfile AND pipfile.lock',
132
- constantsHowToRunHeader: 'How to run:',
133
- constantsHowToRunDev1: 'Begin with contrast auth to authenticate the CLI to perform actions',
134
- constantsHowToRunDev2: 'After successful auth try the following command: contrast scan -f "<file>"',
135
75
  constantsHowToRunDev3: 'Allowable languages are java (.jar and .war) and javascript (.js or .zip), if the language is not autodetected please use --language to specify',
136
76
  constantsOptions: 'Options',
137
- constantsSpecialCharacterWarning: 'Please Note: Parameters may need to be quoted to avoid issues with special characters.',
138
77
  constantsProxyKey: 'Path to the Certificate Key',
139
78
  constantsProxyCert: 'Path to the Cert file',
140
79
  constantsProxyCaCert: 'Path to the CaCert file',
141
80
  goReadProjectFile: 'Failed to read the project file @ "%s" because: "%s"',
142
- mavenDependencyTreeNonZero: 'Building maven dependancy tree failed with a non 0 exit code',
81
+ mavenDependencyTreeNonZero: 'Building maven dependency tree failed with a non 0 exit code',
143
82
  gradleWrapperUnavailable: 'Gradle wrapper not found in root of project. Please ensure gradlew or gradlew.bat is in root of the project.',
144
- gradleDependencyTreeNonZero: "Building gradle dependancy tree failed with a non 0 exit code. \n Please check you have the correct version of Java installed to compile your project? \n If running against a muti module project ensure you are using the '--sub-project' flag",
83
+ gradleDependencyTreeNonZero: "Building gradle dependency tree failed with a non 0 exit code. \n Please check you have the correct version of Java installed to compile your project? \n If running against a muti module project ensure you are using the '--sub-project' flag",
145
84
  constantsMetadata: 'Define a set of key=value pairs (which conforms to RFC 2253) for specifying user-defined metadata associated with the application.',
146
85
  constantsTags: 'Apply labels to an application. Labels must be formatted as a comma-delimited list. Example - label1,label2,label3',
147
86
  constantsCode: 'Add the application code this application should use in the Contrast UI',
148
- constantsIgnoreCertErrors: 'For EOP users with a local Teamserver install, this will bypass the SSL certificate and recognise a self signed certificate.',
87
+ constantsMavenSettingsPath: 'Path to maven settings',
88
+ constantsCertSelfSigned: 'For EOP users with a local Teamserver install, this will bypass the SSL certificate and recognise a self signed certificate.',
149
89
  constantsSave: 'Saves the Scan Results SARIF to file.',
150
90
  scanLabel: "adds a label to the scan - defaults to 'Started by CLI tool at current date'",
151
91
  constantsIgnoreDev: 'Excludes developer dependencies from the results. All dependencies are included by default.',
152
92
  constantsCommands: 'Commands',
153
93
  constantsScanOptions: 'Scan Options',
154
- sbomRetrievalError: 'Unable to retrieve Software Bill of Materials (SBOM)',
94
+ constantsAdvancedOptions: 'Advanced',
155
95
  foundExistingProjectScan: 'Found existing project...',
156
96
  projectCreatedScan: 'Project created',
157
97
  uploadingScan: 'Uploading file to scan.',
@@ -182,8 +122,6 @@ const en_locales = () => {
182
122
  configName: 'config',
183
123
  helpName: 'help',
184
124
  scanOptionsLanguageSummary: 'Valid values are JAVA, JAVASCRIPT and DOTNET',
185
- scanOptionsLanguageSummaryOptional: 'Language of file to send for analysis. ',
186
- scanOptionsLanguageSummaryRequired: 'If you scan a .zip file or you use the --file option.',
187
125
  scanOptionsTimeoutSummary: 'Time in seconds to wait for scan to complete. Default value is 300 seconds.',
188
126
  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.',
189
127
  scanOptionsVerboseSummary: ' Returns extended information to the terminal.',
@@ -203,12 +141,8 @@ const en_locales = () => {
203
141
  ' to learn more about the capabilities.',
204
142
  authWaitingMessage: 'Waiting for auth...',
205
143
  authTimedOutMessage: 'Auth Timed out, try again',
206
- zipErrorScan: 'We only support zip files for JAVASCRIPT language, please set the flag --language JAVASCRIPT',
207
- unknownFileErrorScan: 'Unsupported file selected for Scan.',
208
144
  foundScanFile: 'Found: %s',
209
145
  foundDetailedVulnerabilities: chalk.bold('%s') + ' | ' + chalk.bold('%s') + ' | %s | %s | %s ',
210
- requiredParams: 'All required parameters are not present.',
211
- timeoutScan: 'Timeout set to 5 minutes.',
212
146
  searchingScanFileDirectory: 'Searching for file to scan from %s...',
213
147
  searchingAuditFileDirectory: 'Searching for package manager files from %s...',
214
148
  scanHeader: 'Contrast Scan CLI',
@@ -216,11 +150,9 @@ const en_locales = () => {
216
150
  lambdaHeader: 'Contrast Lambda CLI',
217
151
  lambdaSummary: 'Performs static security scan on an AWS Lambda Function.\nProduces CVE (Vulnerable Dependencies) and Least Privilege violations/remediation results.',
218
152
  lambdaUsage: 'contrast lambda --function-name <function> [options]',
219
- lambdaPrerequisitesContent: '',
220
153
  lambdaPrerequisitesContentLambdaLanguages: 'Supported runtimes: Java & Python',
221
154
  lambdaPrerequisitesContentLambdaDescriptionTitle: 'AWS Requirements\n',
222
155
  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',
223
- scanFileNameOption: '-f, --file',
224
156
  lambdaFunctionNameOption: '-f, --function-name',
225
157
  lambdaListFunctionsOption: '-l, --list-functions',
226
158
  lambdaEndpointOption: '-e, --endpoint-url',
@@ -238,11 +170,9 @@ const en_locales = () => {
238
170
  lambdaVerbosSummery: 'Returns extended information to the terminal.',
239
171
  configNotFound: 'Configuration details not found. Try authenticating by using ‘contrast auth’.',
240
172
  redirectAuth: '\nOpening the authentication page in your web browser.\nSign in and complete the steps.\nReturn here to start using Contrast.\n\nIf your browser has trouble loading, try this:\n%s \n',
241
- scanZipError: 'A .zip archive can be used for Javascript Scan. Archive found %s does not contain .JS files for Scan.',
242
173
  fileNotExist: 'File specified does not exist, please check and try again.',
243
174
  scanFileIsEmpty: 'File specified is empty. Please choose another.',
244
175
  fileHasWhiteSpacesError: 'File cannot have spaces, please rename or choose another file to Scan.',
245
- zipFileException: 'Error reading zip file',
246
176
  connectionError: 'An error has occurred when trying to get the Project Id please check your internet connection or provide the Project Id manually',
247
177
  internalServerErrorHeader: '500 error - Internal server error',
248
178
  resourceLockedErrorHeader: '423 error - Resource is locked',
@@ -271,20 +201,19 @@ const en_locales = () => {
271
201
  scanNoVulnerabilitiesFoundGoodWork: ' Keep up the good work.',
272
202
  scanNoFiletypeSpecifiedForSave: 'Please specify file type to save results to, accepted value is SARIF',
273
203
  auditSBOMSaveSuccess: '\n Software Bill of Materials (SBOM) saved successfully',
274
- auditNoFiletypeSpecifiedForSave: `\n ${chalk.yellow.bold('No file type specified for --save option to save audit results to. Use audit --help to see valid --save options.')}`,
275
204
  auditBadFiletypeSpecifiedForSave: `\n ${chalk.yellow.bold('Bad file type specified for --save option. Use audit --help to see valid --save options.')}`,
276
205
  auditServicesMessageForTS: 'View your vulnerable library list or full dependency tree in Contrast:',
277
- auditReportWaiting: 'Waiting for report...',
278
- auditReportFail: 'Report Retrieval Failed, please try again',
279
- auditReportSuccessMessage: 'Report successfully retrieved',
280
206
  auditReportFailureMessage: 'Unable to generate library report',
281
207
  auditSCAAnalysisBegins: 'Contrast SCA audit started',
282
208
  auditSCAAnalysisComplete: 'Contrast audit complete',
283
- commonHelpHeader: 'Need More Help?',
209
+ commonHelpHeader: 'Need More Help? NEW users',
210
+ commonHelpEnterpriseHeader: 'Existing Contrast Licensed user?',
284
211
  commonHelpCheckOutHeader: chalk.hex('#9DC184')('Check out:'),
285
212
  commonHelpCheckOutText: ' https://support.contrastsecurity.com',
286
213
  commonHelpLearnMoreHeader: chalk.hex('#9DC184')('Learn more at:'),
287
- commonHelpLearnMoreText: ' https://developer.contrastsecurity.com',
214
+ commonHelpLearnMoreEnterpriseHeader: chalk.hex('#9DC184')('Read our docs:'),
215
+ commonHelpLearnMoreText: ' https://www.contrastsecurity.com/developer ',
216
+ commonHelpLearnMoreEnterpriseText: ' https://docs.contrastsecurity.com/en/run-contrast-cli.html ',
288
217
  commonHelpJoinDiscussionHeader: chalk.hex('#9DC184')('Join the discussion:'),
289
218
  commonHelpJoinDiscussionText: ' https://dev.to/codesec',
290
219
  ...lambda
@@ -81,6 +81,7 @@ const lambdaUsageGuide = (0, command_line_usage_1.default)([
81
81
  { name: i18n_1.default.__('lambdaHelpOption'), summary: i18n_1.default.__('helpSummary') }
82
82
  ]
83
83
  },
84
- (0, commonHelp_1.commonHelpLinks)()
84
+ (0, commonHelp_1.commonHelpLinks)()[0],
85
+ (0, commonHelp_1.commonHelpLinks)()[1]
85
86
  ]);
86
87
  exports.lambdaUsageGuide = lambdaUsageGuide;
@@ -23,7 +23,7 @@ const oraWrapper_1 = __importDefault(require("../utils/oraWrapper"));
23
23
  const analytics_1 = require("./analytics");
24
24
  const types_1 = require("./types");
25
25
  const constants_2 = require("../constants/constants");
26
- const chalk_1 = __importDefault(require("chalk"));
26
+ const commonHelp_1 = require("../common/commonHelp");
27
27
  const failedStates = [
28
28
  'UNSUPPORTED',
29
29
  'EXCLUDED',
@@ -110,7 +110,7 @@ const processLambda = async (argv) => {
110
110
  }
111
111
  await (0, analytics_1.postAnalytics)(endCommandAnalytics).catch((error) => {
112
112
  });
113
- postRunMessage();
113
+ (0, commonHelp_1.postRunMessage)('lambda');
114
114
  if (errorMsg) {
115
115
  process.exit(1);
116
116
  }
@@ -193,8 +193,3 @@ const handleLambdaHelp = () => {
193
193
  printHelpMessage();
194
194
  process.exit(0);
195
195
  };
196
- const postRunMessage = () => {
197
- console.log('\n' + chalk_1.default.underline.bold('Other Codesec Features:'));
198
- console.log("'contrast scan' to run CodeSec’s industry leading SAST scanner");
199
- console.log("'contrast audit' to find vulnerabilities in your open source dependencies\n");
200
- };
@@ -1,8 +1,11 @@
1
1
  "use strict";
2
2
  const child_process = require('child_process');
3
+ const spawn = require('cross-spawn');
3
4
  const path = require('path');
4
5
  const i18n = require('i18n');
5
6
  const fs = require('fs');
7
+ const readLine = require('readline');
8
+ const paramHandler = require('../../utils/paramsUtil/paramHandler');
6
9
  const MAVEN = 'maven';
7
10
  const GRADLE = 'gradle';
8
11
  const determineProjectTypeAndCwd = (files, config) => {
@@ -23,15 +26,20 @@ const determineProjectTypeAndCwd = (files, config) => {
23
26
  };
24
27
  const buildMaven = (config, projectData, timeout) => {
25
28
  let cmdStdout;
26
- let mvn_settings = '';
27
29
  try {
30
+ let command = 'mvn';
31
+ let args = ['dependency:tree', '-B'];
28
32
  if (config.mavenSettingsPath) {
29
- mvn_settings = ' -s ' + config.mavenSettingsPath;
33
+ args.push('-s');
34
+ args.push(config.mavenSettingsPath);
30
35
  }
31
- cmdStdout = child_process.execSync('mvn dependency:tree -B' + mvn_settings, {
36
+ cmdStdout = spawn
37
+ .sync(command, args, {
38
+ env: process.env,
32
39
  cwd: projectData.cwd,
33
40
  timeout
34
- });
41
+ })
42
+ .stdout.toString();
35
43
  return cmdStdout.toString();
36
44
  }
37
45
  catch (err) {
@@ -103,7 +111,34 @@ const getJavaBuildDeps = (config, files) => {
103
111
  console.log(err.message.toString());
104
112
  }
105
113
  };
114
+ const agreementPrompt = async (config) => {
115
+ const rl = readLine.createInterface({
116
+ input: process.stdin,
117
+ output: process.stdout
118
+ });
119
+ return new Promise((resolve, reject) => {
120
+ rl.question('❔ Do you want to continue? Type Y or N', async (input) => {
121
+ if (input.toLowerCase() === 'yes' || input.toLowerCase() === 'y') {
122
+ config.javaAgreement = paramHandler.setAgreement(true);
123
+ rl.close();
124
+ resolve(config);
125
+ }
126
+ else if (input.toLowerCase() === 'no' || input.toLowerCase() === 'n') {
127
+ rl.close();
128
+ resolve(process.exit(1));
129
+ }
130
+ else {
131
+ rl.close();
132
+ console.log('Invalid Input: Exiting');
133
+ resolve(process.exit(1));
134
+ }
135
+ });
136
+ }).catch(e => {
137
+ throw e;
138
+ });
139
+ };
106
140
  module.exports = {
107
141
  getJavaBuildDeps,
108
- determineProjectTypeAndCwd
142
+ determineProjectTypeAndCwd,
143
+ agreementPrompt
109
144
  };
@@ -3,10 +3,13 @@ const analysis = require('./analysis');
3
3
  const { parseBuildDeps } = require('./javaBuildDepsParser');
4
4
  const { createJavaTSMessage } = require('../common/formatMessage');
5
5
  const { parseDependenciesForSCAServices } = require('../common/scaParserForGoAndJava');
6
- const javaAnalysis = (config, languageFiles) => {
6
+ const chalk = require('chalk');
7
+ const _ = require('lodash');
8
+ const javaAnalysis = async (config, languageFiles) => {
7
9
  languageFiles.JAVA.forEach(file => {
8
10
  file.replace('build.gradle.kts', 'build.gradle');
9
11
  });
12
+ await getAgreement(config);
10
13
  const javaDeps = buildJavaTree(config, languageFiles.JAVA);
11
14
  if (config.experimental) {
12
15
  return parseDependenciesForSCAServices(javaDeps);
@@ -15,10 +18,19 @@ const javaAnalysis = (config, languageFiles) => {
15
18
  return createJavaTSMessage(javaDeps);
16
19
  }
17
20
  };
21
+ const getAgreement = async (config) => {
22
+ console.log(chalk.bold('Java project detected'));
23
+ console.log('Java analysis uses maven / gradle which are potentially susceptible to command injection. Be sure that the code you are running Contrast CLI on is trusted before continuing.');
24
+ if (!process.env.CI && !config?.javaAgreement) {
25
+ return await analysis.agreementPrompt(config);
26
+ }
27
+ return config;
28
+ };
18
29
  const buildJavaTree = (config, files) => {
19
30
  const javaBuildDeps = analysis.getJavaBuildDeps(config, files);
20
31
  return parseBuildDeps(config, javaBuildDeps);
21
32
  };
22
33
  module.exports = {
23
- javaAnalysis
34
+ javaAnalysis,
35
+ getAgreement
24
36
  };
@@ -1,8 +1,16 @@
1
1
  "use strict";
2
2
  const i18n = require('i18n');
3
3
  const fileFinder = require('./fileUtils');
4
- const rootFile = require('../audit/languageAnalysisEngine/getProjectRootFilenames');
5
- const path = require('path');
4
+ const autoDetectFingerprintInfo = async (filePath) => {
5
+ let complexObj = await fileFinder.findAllFiles(filePath);
6
+ let result = [];
7
+ let count = 0;
8
+ complexObj.forEach(i => {
9
+ count++;
10
+ result.push({ filePath: i, id: count.toString() });
11
+ });
12
+ return result;
13
+ };
6
14
  const autoDetectFileAndLanguage = async (configToUse) => {
7
15
  const entries = await fileFinder.findFile();
8
16
  if (entries.length === 1) {
@@ -43,6 +51,19 @@ const hasWhiteSpace = s => {
43
51
  const filename = s.split('/').pop();
44
52
  return filename.indexOf(' ') >= 0;
45
53
  };
54
+ const dealWithMultiJava = filesFound => {
55
+ let hasMultiJava = filesFound.filter(data => {
56
+ return (Object.keys(data)[0] === 'JAVA' &&
57
+ Object.values(data)[0].includes('build.gradle') &&
58
+ Object.values(data)[0].includes('pom.xml'));
59
+ }).length > 0;
60
+ if (hasMultiJava) {
61
+ console.log('Multiple Java language dependency files detected');
62
+ console.log('Please use --file to audit one only. \nExample: contrast audit --file pom.xml');
63
+ process.exit(1);
64
+ }
65
+ return false;
66
+ };
46
67
  const errorOnFileDetection = entries => {
47
68
  if (entries.length > 1) {
48
69
  console.log(i18n.__('searchingDirectoryScan'));
@@ -78,5 +99,7 @@ module.exports = {
78
99
  autoDetectFileAndLanguage,
79
100
  errorOnFileDetection,
80
101
  autoDetectAuditFilesAndLanguages,
81
- errorOnAuditFileDetection
102
+ errorOnAuditFileDetection,
103
+ autoDetectFingerprintInfo,
104
+ dealWithMultiJava
82
105
  };
@@ -10,6 +10,28 @@ const findFile = async () => {
10
10
  onlyFiles: true
11
11
  });
12
12
  };
13
+ const findAllFiles = async (filePath) => {
14
+ const result = await fg([
15
+ '**/pom.xml',
16
+ '**/build.gradle',
17
+ '**/build.gradle.kts',
18
+ '**/package.json',
19
+ '**/Pipfile',
20
+ '**/*.csproj',
21
+ '**/Gemfile',
22
+ '**/go.mod'
23
+ ], {
24
+ dot: false,
25
+ deep: 2,
26
+ onlyFiles: true,
27
+ absolute: true,
28
+ cwd: filePath ? filePath : process.cwd()
29
+ });
30
+ if (result.length > 0) {
31
+ return result;
32
+ }
33
+ return [];
34
+ };
13
35
  const findFilesJava = async (languagesFound, filePath) => {
14
36
  const result = await fg(['**/pom.xml', '**/build.gradle', '**/build.gradle.kts'], {
15
37
  dot: false,
@@ -136,5 +158,6 @@ module.exports = {
136
158
  findFilesPhp,
137
159
  findFilesRuby,
138
160
  findFilesDotNet,
139
- fileIsEmpty
161
+ fileIsEmpty,
162
+ findAllFiles
140
163
  };
package/dist/scan/help.js CHANGED
@@ -29,14 +29,21 @@ const scanUsageGuide = commandLineUsage([
29
29
  'proxy',
30
30
  'help',
31
31
  'ff',
32
- 'ignore-cert-errors',
32
+ 'cert-self-signed',
33
+ 'key',
34
+ 'cacert',
35
+ 'cert',
33
36
  'verbose',
34
37
  'debug',
35
- 'experimental',
36
- 'application-name'
38
+ 'experimental'
37
39
  ]
38
40
  },
39
- commonHelpLinks()
41
+ {
42
+ header: i18n.__('constantsAdvancedOptions'),
43
+ optionList: constants.commandLineDefinitions.scanAdvancedOptionDefinitionsForHelp
44
+ },
45
+ commonHelpLinks()[0],
46
+ commonHelpLinks()[1]
40
47
  ]);
41
48
  module.exports = {
42
49
  scanUsageGuide
@@ -3,7 +3,7 @@ const fs = require('fs');
3
3
  const writeResultsToFile = async (responseBody, name = 'results.sarif') => {
4
4
  try {
5
5
  fs.writeFileSync(name, JSON.stringify(responseBody, null, 2));
6
- console.log(`Scan Results saved to ${name}`);
6
+ return name;
7
7
  }
8
8
  catch (err) {
9
9
  console.log('Error writing Scan Results to file');
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  const HttpClient = require('./../common/HTTPClient');
3
- const { badRequestError, unauthenticatedError, forbiddenError, proxyError, genericError, maxAppError } = require('../common/errorHandling');
3
+ const { badRequestError, unauthenticatedError, forbiddenError, proxyError, genericError, maxAppError, snapshotFailureError, vulnerabilitiesFailureError, reportFailureError, parametersError, invalidHostNameError } = require('../common/errorHandling');
4
4
  const handleResponseErrors = (res, api) => {
5
5
  if (res.statusCode === 400) {
6
6
  api === 'catalogue' ? badRequestError(true) : badRequestError(false);
@@ -17,7 +17,22 @@ const handleResponseErrors = (res, api) => {
17
17
  else if (res.statusCode === 412) {
18
18
  maxAppError();
19
19
  }
20
+ else if (res.statusCode === 301) {
21
+ invalidHostNameError(res.statusCode);
22
+ }
23
+ else if (res.statusCode === 302) {
24
+ parametersError(res.statusCode);
25
+ }
20
26
  else {
27
+ if (api === 'snapshot' || api === 'catalogue') {
28
+ snapshotFailureError();
29
+ }
30
+ if (api === 'vulnerabilities') {
31
+ vulnerabilitiesFailureError();
32
+ }
33
+ if (api === 'report') {
34
+ reportFailureError();
35
+ }
21
36
  console.log(res.statusCode);
22
37
  genericError(res);
23
38
  }
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  const { featuresTeamServer } = require('./capabilities');
3
3
  const semver = require('semver');
4
- const { handleResponseErrors } = require('../common/errorHandling');
5
4
  const commonApi = require('./commonApi');
6
5
  const { isNil } = require('lodash');
7
6
  const getGlobalProperties = async (config) => {
@@ -13,7 +12,7 @@ const getGlobalProperties = async (config) => {
13
12
  return res.body;
14
13
  }
15
14
  else {
16
- handleResponseErrors(res, 'globalProperties');
15
+ commonApi.handleResponseErrors(res, 'globalProperties');
17
16
  }
18
17
  })
19
18
  .catch(err => {
@@ -15,4 +15,15 @@ const getAuth = () => {
15
15
  }
16
16
  return ContrastConfToUse;
17
17
  };
18
- module.exports = { getAuth: getAuth };
18
+ const getAgreement = () => {
19
+ const ContrastConf = config.localConfig(APP_NAME, APP_VERSION);
20
+ let ContrastConfToUse = {};
21
+ ContrastConfToUse.javaAgreement = ContrastConf.get('javaAgreement');
22
+ return ContrastConfToUse;
23
+ };
24
+ const setAgreement = agreement => {
25
+ const ContrastConf = config.localConfig(APP_NAME, APP_VERSION);
26
+ ContrastConf.set('javaAgreement', agreement);
27
+ return agreement;
28
+ };
29
+ module.exports = { getAuth, getAgreement, setAgreement };
@@ -22,4 +22,10 @@ const getAuth = params => {
22
22
  process.exit(1);
23
23
  }
24
24
  };
25
- module.exports = { getAuth: getAuth };
25
+ const getAgreement = () => {
26
+ return configStoreParams.getAgreement();
27
+ };
28
+ const setAgreement = answer => {
29
+ return configStoreParams.setAgreement(answer);
30
+ };
31
+ module.exports = { getAuth, getAgreement, setAgreement };
@@ -8,7 +8,8 @@ const saveScanFile = async (config, scanResults) => {
8
8
  const scanId = scanResults.scanDetail.id;
9
9
  const client = commonApi.getHttpClient(config);
10
10
  const rawResults = await client.getSpecificScanResultSarif(config, scanId);
11
- await saveResults.writeResultsToFile(rawResults?.body);
11
+ const name = await saveResults.writeResultsToFile(rawResults?.body);
12
+ console.log(`Scan Results saved to ${name}`);
12
13
  }
13
14
  else {
14
15
  console.log(i18n.__('scanNoFiletypeSpecifiedForSave'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/contrast",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "Contrast Security's command line tool",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -54,6 +54,7 @@
54
54
  "command-line-args": "^5.2.1",
55
55
  "command-line-usage": "^6.1.3",
56
56
  "conf": "^10.1.2",
57
+ "cross-spawn": "^7.0.3",
57
58
  "dotenv": "^16.0.0",
58
59
  "fast-glob": "^3.2.11",
59
60
  "gradle-to-js": "^2.0.1",
@@ -45,7 +45,7 @@ const tryRetrieveAppIdFromMessages = messages => {
45
45
  }
46
46
 
47
47
  module.exports = {
48
- catalogueApplication: catalogueApplication,
48
+ catalogueApplication,
49
49
  doesMessagesContainAppId,
50
50
  tryRetrieveAppIdFromMessages
51
51
  }