@contrast/contrast 1.0.3 → 1.0.4

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 (62) hide show
  1. package/.prettierignore +1 -0
  2. package/README.md +20 -14
  3. package/dist/audit/languageAnalysisEngine/{langugageAnalysisFactory.js → languageAnalysisFactory.js} +2 -12
  4. package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +62 -234
  5. package/dist/audit/languageAnalysisEngine/report/models/reportLibraryModel.js +19 -0
  6. package/dist/audit/languageAnalysisEngine/report/models/reportListModel.js +24 -0
  7. package/dist/audit/languageAnalysisEngine/report/models/reportSeverityModel.js +10 -0
  8. package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +24 -129
  9. package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +85 -0
  10. package/dist/audit/languageAnalysisEngine/sendSnapshot.js +3 -1
  11. package/dist/commands/audit/auditController.js +6 -3
  12. package/dist/commands/scan/processScan.js +4 -3
  13. package/dist/common/HTTPClient.js +19 -26
  14. package/dist/common/versionChecker.js +14 -12
  15. package/dist/constants/constants.js +1 -1
  16. package/dist/constants/lambda.js +3 -1
  17. package/dist/constants/locales.js +17 -10
  18. package/dist/constants.js +5 -1
  19. package/dist/index.js +2 -2
  20. package/dist/lambda/help.js +22 -14
  21. package/dist/lambda/lambda.js +6 -0
  22. package/dist/scan/models/groupedResultsModel.js +10 -0
  23. package/dist/scan/models/resultContentModel.js +2 -0
  24. package/dist/scan/models/scanResultsModel.js +11 -0
  25. package/dist/scan/scan.js +90 -95
  26. package/dist/scan/scanConfig.js +1 -1
  27. package/dist/utils/getConfig.js +3 -0
  28. package/package.json +2 -2
  29. package/src/audit/languageAnalysisEngine/{langugageAnalysisFactory.js → languageAnalysisFactory.js} +2 -16
  30. package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +127 -0
  31. package/src/audit/languageAnalysisEngine/report/models/reportLibraryModel.ts +30 -0
  32. package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +32 -0
  33. package/src/audit/languageAnalysisEngine/report/models/reportSeverityModel.ts +9 -0
  34. package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +56 -0
  35. package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +110 -0
  36. package/src/audit/languageAnalysisEngine/sendSnapshot.js +3 -1
  37. package/src/commands/audit/auditController.ts +12 -3
  38. package/src/commands/scan/processScan.js +4 -6
  39. package/src/common/HTTPClient.js +31 -38
  40. package/src/common/errorHandling.ts +0 -1
  41. package/src/common/versionChecker.ts +24 -22
  42. package/src/constants/constants.js +1 -1
  43. package/src/constants/lambda.js +3 -1
  44. package/src/constants/locales.js +20 -10
  45. package/src/constants.js +7 -1
  46. package/src/index.ts +2 -3
  47. package/src/lambda/help.ts +22 -14
  48. package/src/lambda/lambda.ts +8 -0
  49. package/src/scan/models/groupedResultsModel.ts +18 -0
  50. package/src/scan/models/resultContentModel.ts +86 -0
  51. package/src/scan/models/scanResultsModel.ts +52 -0
  52. package/src/scan/scan.ts +192 -0
  53. package/src/scan/scanConfig.js +1 -1
  54. package/src/scan/scanController.js +2 -0
  55. package/src/utils/getConfig.ts +10 -0
  56. package/dist/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +0 -17
  57. package/dist/audit/languageAnalysisEngine/report/newReportingFeature.js +0 -81
  58. package/src/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +0 -27
  59. package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.js +0 -303
  60. package/src/audit/languageAnalysisEngine/report/newReportingFeature.js +0 -124
  61. package/src/audit/languageAnalysisEngine/report/reportingFeature.js +0 -190
  62. package/src/scan/scan.js +0 -195
@@ -0,0 +1,110 @@
1
+ import {
2
+ ReportCVEModel,
3
+ ReportLibraryModel
4
+ } from '../models/reportLibraryModel'
5
+ import { ReportSeverityModel } from '../models/reportSeverityModel'
6
+ import languageAnalysisEngine from '../../../languageAnalysisEngine/constants'
7
+ const {
8
+ supportedLanguages: { GO }
9
+ } = languageAnalysisEngine
10
+
11
+ export function findHighestSeverityCVE(cveArray: ReportCVEModel[]) {
12
+ if (
13
+ cveArray.find(
14
+ cve =>
15
+ cve.cvss3SeverityCode === 'CRITICAL' || cve.severityCode === 'CRITICAL'
16
+ )
17
+ ) {
18
+ return new ReportSeverityModel('CRITICAL', 1)
19
+ } else if (
20
+ cveArray.find(
21
+ cve => cve.cvss3SeverityCode === 'HIGH' || cve.severityCode === 'HIGH'
22
+ )
23
+ ) {
24
+ return new ReportSeverityModel('HIGH', 2)
25
+ } else if (
26
+ cveArray.find(
27
+ cve => cve.cvss3SeverityCode === 'MEDIUM' || cve.severityCode === 'MEDIUM'
28
+ )
29
+ ) {
30
+ return new ReportSeverityModel('MEDIUM', 3)
31
+ } else if (
32
+ cveArray.find(
33
+ cve => cve.cvss3SeverityCode === 'LOW' || cve.severityCode === 'LOW'
34
+ )
35
+ ) {
36
+ return new ReportSeverityModel('LOW', 4)
37
+ } else if (
38
+ cveArray.find(
39
+ cve => cve.cvss3SeverityCode === 'NOTE' || cve.severityCode === 'NOTE'
40
+ )
41
+ ) {
42
+ return new ReportSeverityModel('NOTE', 5)
43
+ }
44
+ }
45
+
46
+ export function convertGenericToTypedLibraries(libraries: any) {
47
+ return Object.entries(libraries).map(([name, cveArray]) => {
48
+ return new ReportLibraryModel(name, cveArray as ReportCVEModel[])
49
+ })
50
+ }
51
+
52
+ export function severityCount(vulnerableLibraries: ReportLibraryModel[]) {
53
+ const severityCount = {
54
+ critical: 0,
55
+ high: 0,
56
+ medium: 0,
57
+ low: 0,
58
+ note: 0
59
+ }
60
+
61
+ vulnerableLibraries.forEach(lib => {
62
+ lib.cveArray.forEach(cve => {
63
+ if (
64
+ cve.cvss3SeverityCode === 'CRITICAL' ||
65
+ cve.severityCode === 'CRITICAL'
66
+ ) {
67
+ severityCount['critical'] += 1
68
+ } else if (
69
+ cve.cvss3SeverityCode === 'HIGH' ||
70
+ cve.severityCode === 'HIGH'
71
+ ) {
72
+ severityCount['high'] += 1
73
+ } else if (
74
+ cve.cvss3SeverityCode === 'MEDIUM' ||
75
+ cve.severityCode === 'MEDIUM'
76
+ ) {
77
+ severityCount['medium'] += 1
78
+ } else if (
79
+ cve.cvss3SeverityCode === 'LOW' ||
80
+ cve.severityCode === 'LOW'
81
+ ) {
82
+ severityCount['low'] += 1
83
+ } else if (
84
+ cve.cvss3SeverityCode === 'NOTE' ||
85
+ cve.severityCode === 'NOTE'
86
+ ) {
87
+ severityCount['note'] += 1
88
+ }
89
+ })
90
+ })
91
+
92
+ return severityCount
93
+ }
94
+
95
+ export function findNameAndVersion(library: ReportLibraryModel, config: any) {
96
+ if (config.language.toUpperCase() === GO) {
97
+ const nameVersion = library.name.split('@')
98
+ const name = nameVersion[0]
99
+ const version = nameVersion[1]
100
+
101
+ return { name, version }
102
+ } else {
103
+ const splitLibraryName = library.name.split('/')
104
+ const nameVersion = splitLibraryName[1].split('@')
105
+ const name = nameVersion[0]
106
+ const version = nameVersion[1]
107
+
108
+ return { name, version }
109
+ }
110
+ }
@@ -34,7 +34,9 @@ const newSendSnapShot = async (analysis, applicationId) => {
34
34
  // console.log(prettyjson.render(requestBody))
35
35
  // }
36
36
  if (res.statusCode === 201) {
37
- displaySnapshotSuccessMessage(analysis.config)
37
+ if (analysis.config.host !== 'https://ce.contrastsecurity.com/') {
38
+ displaySnapshotSuccessMessage(analysis.config)
39
+ }
38
40
  return res.body
39
41
  } else {
40
42
  handleResponseErrors(res, 'snapshot')
@@ -1,7 +1,8 @@
1
1
  import { catalogueApplication } from '../../audit/catalogueApplication/catalogueApplication'
2
2
  import commonApi from '../../audit/languageAnalysisEngine/commonApi'
3
+
3
4
  const identifyLanguageAE = require('./../../audit/languageAnalysisEngine')
4
- const languageFactory = require('./../../audit/languageAnalysisEngine/langugageAnalysisFactory')
5
+ const languageFactory = require('../../audit/languageAnalysisEngine/languageAnalysisFactory')
5
6
 
6
7
  const dealWithNoAppId = async (config: { [x: string]: string }) => {
7
8
  let appID
@@ -10,10 +11,18 @@ const dealWithNoAppId = async (config: { [x: string]: string }) => {
10
11
  if (!appID && config.applicationName) {
11
12
  return await catalogueApplication(config)
12
13
  }
14
+ // @ts-ignore
13
15
  } catch (e) {
14
- console.log(e)
16
+ // @ts-ignore
17
+ if (e.toString().includes('tunneling socket could not be established')) {
18
+ // @ts-ignore
19
+ console.log(e.message)
20
+ console.log(
21
+ 'There seems to be an issue with your proxy, please check and try again'
22
+ )
23
+ }
24
+ process.exit(1)
15
25
  }
16
- console.log(appID)
17
26
  return appID
18
27
  }
19
28
 
@@ -1,18 +1,16 @@
1
1
  const { startScan } = require('../../scan/scanController')
2
- const { formatScanOutput } = require('../../scan/scan')
3
2
  const { scanUsageGuide } = require('../../scan/help')
4
3
  const scanConfig = require('../../scan/scanConfig')
5
4
  const { saveScanFile } = require('../../utils/saveFile')
5
+ const { ScanResultsModel } = require('../../scan/models/scanResultsModel')
6
+ const { formatScanOutput } = require('../../scan/scan')
6
7
 
7
8
  const processScan = async argvMain => {
8
9
  let config = scanConfig.getScanConfig(argvMain)
9
10
 
10
- let scanResults = await startScan(config)
11
+ let scanResults = new ScanResultsModel(await startScan(config))
11
12
  if (scanResults) {
12
- formatScanOutput(
13
- scanResults?.projectOverview,
14
- scanResults?.scanResultsInstances
15
- )
13
+ formatScanOutput(scanResults)
16
14
  }
17
15
 
18
16
  if (config.save !== undefined) {
@@ -106,7 +106,9 @@ HTTPClient.prototype.getScanId = function getScanId(config, codeArtifactId) {
106
106
  options.url = url
107
107
  options.body = {
108
108
  codeArtifactId: codeArtifactId,
109
- label: `Started by CLI tool at ${new Date().toString()}`
109
+ label: config.label
110
+ ? config.label
111
+ : `Started by CLI tool at ${new Date().toString()}`
110
112
  }
111
113
  return requestUtils.sendRequest({ method: 'post', options })
112
114
  }
@@ -188,6 +190,9 @@ HTTPClient.prototype.catalogueCommand = function catalogueCommand(config) {
188
190
  }
189
191
 
190
192
  HTTPClient.prototype.sendSnapshot = function sendSnapshot(requestBody, config) {
193
+ if (config.language.toUpperCase() === 'RUBY') {
194
+ console.log('sendSnapshot requestBody', requestBody.snapshot.ruby)
195
+ }
191
196
  const options = _.cloneDeep(this.requestOptions)
192
197
  let url = createSnapshotURL(config)
193
198
  options.url = url
@@ -195,32 +200,22 @@ HTTPClient.prototype.sendSnapshot = function sendSnapshot(requestBody, config) {
195
200
  return requestUtils.sendRequest({ method: 'post', options })
196
201
  }
197
202
 
198
- HTTPClient.prototype.getReport = function getReport(config) {
199
- const options = _.cloneDeep(this.requestOptions)
200
- let url = createReportUrl(config)
201
- options.url = url
202
-
203
- return requestUtils.sendRequest({ method: 'get', options })
204
- }
205
-
206
- HTTPClient.prototype.getSpecificReport = function getSpecificReport(
207
- config,
208
- reportId
209
- ) {
203
+ HTTPClient.prototype.getReportById = function getReportById(config, reportId) {
210
204
  const options = _.cloneDeep(this.requestOptions)
211
- let url = createSpecificReportUrl(config, reportId)
212
- options.url = url
213
-
205
+ if (config.ignoreDev) {
206
+ options.url = createSpecificReportWithProdUrl(config, reportId)
207
+ } else {
208
+ options.url = createSpecificReportUrl(config, reportId)
209
+ }
214
210
  return requestUtils.sendRequest({ method: 'get', options })
215
211
  }
216
212
 
217
213
  HTTPClient.prototype.getLibraryVulnerabilities = function getLibraryVulnerabilities(
218
- requestBody,
219
- config
214
+ config,
215
+ requestBody
220
216
  ) {
221
217
  const options = _.cloneDeep(this.requestOptions)
222
- let url = createLibraryVulnerabilitiesUrl(config)
223
- options.url = url
218
+ options.url = createLibraryVulnerabilitiesUrl(config)
224
219
  options.body = requestBody
225
220
 
226
221
  return requestUtils.sendRequest({ method: 'put', options })
@@ -233,16 +228,16 @@ HTTPClient.prototype.getAppId = function getAppId(config) {
233
228
  return requestUtils.sendRequest({ method: 'get', options })
234
229
  }
235
230
 
236
- HTTPClient.prototype.getDependencyTree = function getReport(
237
- orgUuid,
238
- appId,
239
- reportId
240
- ) {
241
- const options = _.cloneDeep(this.requestOptions)
242
- let url = createGetDependencyTree(options.uri, orgUuid, appId, reportId)
243
- options.url = url
244
- return requestUtils.sendRequest({ method: 'get', options })
245
- }
231
+ // HTTPClient.prototype.getDependencyTree = function getReport(
232
+ // orgUuid,
233
+ // appId,
234
+ // reportId
235
+ // ) {
236
+ // const options = _.cloneDeep(this.requestOptions)
237
+ // let url = createGetDependencyTree(options.uri, orgUuid, appId, reportId)
238
+ // options.url = url
239
+ // return requestUtils.sendRequest({ method: 'get', options })
240
+ // }
246
241
 
247
242
  // serverless - lambda
248
243
  function getServerlessHost(config = {}) {
@@ -379,22 +374,20 @@ function createLibraryVulnerabilitiesUrl(config) {
379
374
  return `${config.host}/Contrast/api/ng/${config.organizationId}/libraries/artifactsByGroupNameVersion`
380
375
  }
381
376
 
382
- function createReportUrl(config) {
383
- return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/${config.applicationId}/reports`
377
+ function createSpecificReportUrl(config, reportId) {
378
+ return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/${config.applicationId}/reports/${reportId}`
384
379
  }
385
380
 
386
- function createSpecificReportUrl(config, reportId) {
387
- return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/${config.applicationId}/reports/${reportId}?nodesToInclude=PROD`
381
+ function createSpecificReportWithProdUrl(config, reportId) {
382
+ return createSpecificReportUrl(config, reportId).concat(
383
+ `?nodesToInclude=PROD`
384
+ )
388
385
  }
389
386
 
390
387
  function createDataUrl() {
391
388
  return `https://ardy.contrastsecurity.com/production`
392
389
  }
393
390
 
394
- const createGetDependencyTree = (protocol, orgUuid, appId, reportId) => {
395
- return `${protocol}/Contrast/api/ng/sca/organizations/${orgUuid}/applications/${appId}/reports/${reportId}`
396
- }
397
-
398
391
  function createSbomCycloneDXUrl(config) {
399
392
  return `${config.host}/Contrast/api/ng/${config.organizationId}/applications/${config.applicationId}/libraries/sbom/cyclonedx`
400
393
  }
@@ -1,5 +1,4 @@
1
1
  import i18n from 'i18n'
2
- import { sortBy } from 'lodash'
3
2
 
4
3
  const handleResponseErrors = (res: any, api: string) => {
5
4
  if (res.statusCode === 400) {
@@ -4,33 +4,35 @@ import boxen from 'boxen'
4
4
  import chalk from 'chalk'
5
5
  import semver from 'semver'
6
6
 
7
- export async function findLatestCLIVersion() {
8
- const latestCLIVersion = await latestVersion('@contrast/contrast')
7
+ export async function findLatestCLIVersion(updateMessageHidden: boolean) {
8
+ if (!updateMessageHidden) {
9
+ const latestCLIVersion = await latestVersion('@contrast/contrast')
9
10
 
10
- if (semver.lt(APP_VERSION, latestCLIVersion)) {
11
- const updateAvailableMessage = `Update available ${chalk.yellow(
12
- APP_VERSION
13
- )} → ${chalk.green(latestCLIVersion)}`
11
+ if (semver.lt(APP_VERSION, latestCLIVersion)) {
12
+ const updateAvailableMessage = `Update available ${chalk.yellow(
13
+ APP_VERSION
14
+ )} → ${chalk.green(latestCLIVersion)}`
14
15
 
15
- const npmUpdateAvailableCommand = `Run ${chalk.cyan(
16
- 'npm i @contrast/contrast -g'
17
- )} to update via npm`
16
+ const npmUpdateAvailableCommand = `Run ${chalk.cyan(
17
+ 'npm i @contrast/contrast -g'
18
+ )} to update via npm`
18
19
 
19
- const homebrewUpdateAvailableCommand = `Run ${chalk.cyan(
20
- 'brew install contrastsecurity/tap/contrast'
21
- )} to update via brew`
20
+ const homebrewUpdateAvailableCommand = `Run ${chalk.cyan(
21
+ 'brew install contrastsecurity/tap/contrast'
22
+ )} to update via brew`
22
23
 
23
- console.log(
24
- boxen(
25
- `${updateAvailableMessage}\n${npmUpdateAvailableCommand}\n\n${homebrewUpdateAvailableCommand}`,
26
- {
27
- titleAlignment: 'center',
28
- margin: 1,
29
- padding: 1,
30
- align: 'center'
31
- }
24
+ console.log(
25
+ boxen(
26
+ `${updateAvailableMessage}\n${npmUpdateAvailableCommand}\n\n${homebrewUpdateAvailableCommand}`,
27
+ {
28
+ titleAlignment: 'center',
29
+ margin: 1,
30
+ padding: 1,
31
+ align: 'center'
32
+ }
33
+ )
32
34
  )
33
- )
35
+ }
34
36
  }
35
37
  }
36
38
 
@@ -13,7 +13,7 @@ const MEDIUM = 'MEDIUM'
13
13
  const HIGH = 'HIGH'
14
14
  const CRITICAL = 'CRITICAL'
15
15
  const APP_NAME = 'contrast'
16
- const APP_VERSION = '1.0.3'
16
+ const APP_VERSION = '1.0.4'
17
17
  const TIMEOUT = 120000
18
18
 
19
19
  const AUTH_UI_URL = 'https://cli-auth.contrastsecurity.com'
@@ -36,11 +36,13 @@ const lambda = {
36
36
  loadingFunctionList: 'Loading lambda function list',
37
37
  functionsFound: '{{count}} functions found',
38
38
  noFunctionsFound: 'No functions found',
39
- failedToLoadFunctions: 'Faled to load lambda functions',
39
+ failedToLoadFunctions: 'Failed to load lambda functions',
40
40
  availableForScan: '{{icon}} {{count}} available for scan',
41
41
  runtimeCount: '----- {{runtime}} ({{count}}) -----',
42
42
 
43
43
  // ====== print vulnerabilities ===== //
44
+ gatherResults: 'Gathering results...',
45
+ doneGatherResults: 'Done gathering results',
44
46
  whatHappenedTitle: 'What happened:',
45
47
  whatHappenedItem: '{{policy}} have:\n{{comments}}\n',
46
48
  recommendation: 'Recommendation:',
@@ -14,8 +14,6 @@ const en_locales = () => {
14
14
  vulnerabilitiesSuccessMessage: ' Vulnerability data successfully retrieved',
15
15
  vulnerabilitiesFailureMessage:
16
16
  ' Unable to retrieve library vulnerabilities from Team Server.',
17
- reportSuccessMessage: ' Report successfully retrieved',
18
- reportFailureMessage: ' Unable to generate library report.',
19
17
  catchErrorMessage: 'Contrast UI error: ',
20
18
  dependenciesNote:
21
19
  'Please Note: We currently only support projects with one .csproj AND *.package.lock.json',
@@ -175,7 +173,7 @@ const en_locales = () => {
175
173
  constantsHeader: 'CodeSec by Contrast Security',
176
174
  constantsPrerequisitesContentScanLanguages: 'Java & JavaScript supported',
177
175
  constantsContrastContent:
178
- 'Use the Contrast CLI to run a scan(Java, JavaScript and .NET ) or lambda command (Java and Python) to find your vulnerabilities and start securing your code.',
176
+ 'Use the Contrast CLI to run a scan (Java, JavaScript and .NET ) or lambda command (Java and Python) to find your vulnerabilities and start securing your code.',
179
177
  constantsUsageGuideContentRecommendation:
180
178
  '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.',
181
179
  constantsPrerequisitesHeader: 'Pre-requisites',
@@ -274,7 +272,9 @@ const en_locales = () => {
274
272
  'Add the application code this application should use in the Contrast UI',
275
273
  constantsIgnoreCertErrors:
276
274
  ' For EOP users with a local Teamserver install, this will bypass the SSL certificate and recognise a self signed certificate.',
277
- constantsSave: ' Saves the Scan Results JSON to file.',
275
+ constantsSave: ' Saves the Scan Results SARIF to file.',
276
+ scanLabel:
277
+ "adds a label to the scan - defaults to 'Started by CLI tool at current date'",
278
278
  constantsIgnoreDev:
279
279
  'Combined with the --report command excludes developer dependencies from the vulnerabilities report. By default all dependencies are included in a report.',
280
280
  constantsCommands: 'Commands',
@@ -284,7 +284,7 @@ const en_locales = () => {
284
284
  ignoreDevDep: 'No private libraries that are not scoped detected',
285
285
  foundExistingProjectScan: 'Found existing project...',
286
286
  projectCreatedScan: 'Project created',
287
- uploadingScan: 'Uploading...',
287
+ uploadingScan: 'Uploading file to scan.',
288
288
  uploadingScanSuccessful: 'Uploaded file successfully.',
289
289
  uploadingScanFail: 'Unable to upload the file.',
290
290
  waitingTimedOut: 'Timed out.',
@@ -296,6 +296,7 @@ const en_locales = () => {
296
296
  'Java Scan requires a .war or .jar file. Javascript Scan requires a .js or .zip file.\nTo start a Scan enter "contrast scan -f <path-to-file>"',
297
297
  populateProjectIdMessage: 'project ID is %s',
298
298
  genericServiceError: 'returned with status code %s',
299
+ projectIdError: 'Your project ID is %s please check this is correct',
299
300
  permissionsError:
300
301
  'You do not have the correct permissions here. \n Contact support@contrastsecurity.com to get this fixed.',
301
302
  scanErrorFileMessage:
@@ -343,14 +344,19 @@ const en_locales = () => {
343
344
  searchingScanFileDirectory: 'Searching for file to scan from %s...',
344
345
  scanHeader: 'Contrast Scan CLI',
345
346
  authHeader: 'Auth',
346
- lambdaHeader: 'Contrast lambda help',
347
+ lambdaHeader: 'Contrast Lambda CLI',
347
348
  lambdaSummary:
348
349
  'Performs static security scan on an AWS Lambda Function.\nProduces CVE (Vulnerable Dependencies) and Least Privilege violations/remediation results.',
349
350
  lambdaUsage: 'contrast lambda --function-name <function> [options]',
350
- lambdaPrerequisitesContent: 'contrast cli',
351
- scanFileNameOption: ' -f, --file',
352
- lambdaFunctionNameOption: ' -f, --function-name',
353
- lambdaListFunctionsOption: ' -l, --list-functions',
351
+ lambdaPrerequisitesContent: '',
352
+ lambdaPrerequisitesContentLambdaLanguages:
353
+ 'Supported runtimes: Java & Python',
354
+ lambdaPrerequisitesContentLambdaDescriptionTitle: 'AWS Requirements\n',
355
+ lambdaPrerequisitesContentLambdaDescription:
356
+ '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ֿ\n - IAM: GetRolePolicy, GetPolicy, GetPolicyVersion, ListRolePolicies, ListAttachedRolePolicies',
357
+ scanFileNameOption: '-f, --file',
358
+ lambdaFunctionNameOption: '-f, --function-name',
359
+ lambdaListFunctionsOption: '-l, --list-functions',
354
360
  lambdaEndpointOption: '-e, --endpoint-url',
355
361
  lambdaRegionOption: '-r, --region',
356
362
  lambdaProfileOption: '-p, --profile',
@@ -422,6 +428,10 @@ const en_locales = () => {
422
428
  auditBadFiletypeSpecifiedForSave: `\n ${chalk.yellow.bold(
423
429
  'Bad file type specified for --save option. Use audit --help to see valid --save options.'
424
430
  )}`,
431
+ auditReportWaiting: 'Waiting for report...',
432
+ auditReportFail: 'Report Retrieval Failed, please try again',
433
+ auditReportSuccessMessage: ' Report successfully retrieved',
434
+ auditReportFailureMessage: ' Unable to generate library report.',
425
435
  ...lambda
426
436
  }
427
437
  }
package/src/constants.js CHANGED
@@ -132,6 +132,11 @@ const scanOptionDefinitions = [
132
132
  description:
133
133
  '{bold ' + i18n.__('constantsOptional') + '}:' + i18n.__('constantsSave')
134
134
  },
135
+ {
136
+ name: 'label',
137
+ description:
138
+ '{bold ' + i18n.__('constantsOptional') + '}:' + i18n.__('scanLabel')
139
+ },
135
140
  {
136
141
  name: 'help',
137
142
  alias: 'h',
@@ -331,7 +336,8 @@ const mainUsageGuide = commandLineUsage([
331
336
  ]
332
337
  },
333
338
  {
334
- content: '{underline https://www.contrastsecurity.com}'
339
+ content:
340
+ '{underline https://developer.contrastsecurity.com/} \n For technical support head to {underline https://support.contrastsecurity.com}'
335
341
  }
336
342
  ])
337
343
 
package/src/index.ts CHANGED
@@ -44,7 +44,7 @@ const start = async () => {
44
44
  argvMain.includes('--version')
45
45
  ) {
46
46
  console.log(APP_VERSION)
47
- await findLatestCLIVersion()
47
+ await findLatestCLIVersion(config.get('updateMessageHidden') as boolean)
48
48
  return
49
49
  }
50
50
 
@@ -53,8 +53,7 @@ const start = async () => {
53
53
 
54
54
  // @ts-ignore
55
55
  if (config.get('numOfRuns') >= 5) {
56
- // @ts-ignore
57
- await findLatestCLIVersion()
56
+ await findLatestCLIVersion(config.get('updateMessageHidden') as boolean)
58
57
  config.set('numOfRuns', 0)
59
58
  }
60
59
 
@@ -8,7 +8,15 @@ const lambdaUsageGuide = commandLineUsage([
8
8
  },
9
9
  {
10
10
  header: i18n.__('constantsPrerequisitesHeader'),
11
- content: [i18n.__('lambdaPrerequisitesContent')]
11
+ content: [
12
+ '{bold ' +
13
+ i18n.__('lambdaPrerequisitesContentLambdaLanguages') +
14
+ '}\n\n' +
15
+ '{bold ' +
16
+ i18n.__('lambdaPrerequisitesContentLambdaDescriptionTitle') +
17
+ '}' +
18
+ i18n.__('lambdaPrerequisitesContentLambdaDescription')
19
+ ]
12
20
  },
13
21
  {
14
22
  header: i18n.__('constantsUsage'),
@@ -18,49 +26,49 @@ const lambdaUsageGuide = commandLineUsage([
18
26
  header: i18n.__('constantsOptions'),
19
27
  content: [
20
28
  {
21
- name: i18n.__('lambdaFunctionNameOption'),
29
+ name: '{bold ' + i18n.__('lambdaFunctionNameOption') + '}',
22
30
  summary: i18n.__('lambdaFunctionNameSummery')
23
31
  },
24
32
  {
25
- name: i18n.__('lambdaListFunctionsOption'),
33
+ name: '{bold ' + i18n.__('lambdaListFunctionsOption') + '}',
26
34
  summary: i18n.__('lambdaListFunctionsSummery')
27
35
  },
28
36
  {
29
- name: i18n.__('lambdaEndpointOption'),
37
+ name: '{bold ' + i18n.__('lambdaEndpointOption') + '}',
30
38
  summary:
31
- '{italic ' +
39
+ '{bold ' +
32
40
  i18n.__('constantsOptional') +
33
41
  '}: ' +
34
42
  i18n.__('lambdaEndpointSummery')
35
43
  },
36
44
  {
37
- name: i18n.__('lambdaRegionOption'),
45
+ name: '{bold ' + i18n.__('lambdaRegionOption') + '}',
38
46
  summary:
39
- '{italic ' +
47
+ '{bold ' +
40
48
  i18n.__('constantsOptional') +
41
49
  '}: ' +
42
50
  i18n.__('lambdaRegionSummery')
43
51
  },
44
52
  {
45
- name: i18n.__('lambdaProfileOption'),
53
+ name: '{bold ' + i18n.__('lambdaProfileOption') + '}',
46
54
  summary:
47
- '{italic ' +
55
+ '{bold ' +
48
56
  i18n.__('constantsOptional') +
49
57
  '}: ' +
50
58
  i18n.__('lambdaProfileSummery')
51
59
  },
52
60
  {
53
- name: i18n.__('lambdaJsonOption'),
61
+ name: '{bold ' + i18n.__('lambdaJsonOption') + '}',
54
62
  summary:
55
- '{italic ' +
63
+ '{bold ' +
56
64
  i18n.__('constantsOptional') +
57
65
  '}: ' +
58
66
  i18n.__('lambdaJsonSummery')
59
67
  },
60
68
  {
61
- name: i18n.__('lambdaVerboseOption'),
69
+ name: '{bold ' + i18n.__('lambdaVerboseOption') + '}',
62
70
  summary:
63
- '{italic ' +
71
+ '{bold ' +
64
72
  i18n.__('constantsOptional') +
65
73
  '}: ' +
66
74
  i18n.__('lambdaVerbosSummery')
@@ -73,7 +81,7 @@ const lambdaUsageGuide = commandLineUsage([
73
81
  ]
74
82
  },
75
83
  {
76
- content: '{underline https://www.contrastsecurity.com}'
84
+ content: '{underline https://www.contrastsecurity.com/developer/codesec}'
77
85
  }
78
86
  ])
79
87
 
@@ -12,6 +12,8 @@ import { requestScanFunctionPost } from './scanRequest'
12
12
  import { getScanResults } from './scanResults'
13
13
  import { printResults } from './utils'
14
14
  import { getAllLambdas, printAvailableLambdas } from './lambdaUtils'
15
+ import { sleep } from '../utils/requestUtils'
16
+ import ora from '../utils/oraWrapper'
15
17
 
16
18
  type LambdaOptions = {
17
19
  functionName?: string
@@ -123,6 +125,12 @@ const actualProcessLambda = async (lambdaOptions: LambdaOptions) => {
123
125
  })
124
126
  }
125
127
 
128
+ // Wait to make sure we will have all the results
129
+ const startGetherResultsSpinner = ora.returnOra(i18n.__('gatherResults'))
130
+ ora.startSpinner(startGetherResultsSpinner)
131
+ await sleep(15 * 1000)
132
+ ora.succeedSpinner(startGetherResultsSpinner, 'Done gathering results')
133
+
126
134
  const resultsResponse = await getScanResults(
127
135
  auth,
128
136
  params,
@@ -0,0 +1,18 @@
1
+ export class GroupedResultsModel {
2
+ ruleId: string
3
+ lineInfoSet: Set<string>
4
+ cwe?: string[]
5
+ owasp?: string[]
6
+ reference?: string[]
7
+ recommendation?: string
8
+ severity?: string
9
+ advice?: string
10
+ learn?: string[]
11
+ issue?: string
12
+ message?: string
13
+
14
+ constructor(ruleId: string) {
15
+ this.ruleId = ruleId
16
+ this.lineInfoSet = new Set<string>
17
+ }
18
+ }