@contrast/contrast 1.0.0

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 (88) hide show
  1. package/README.md +109 -0
  2. package/bin/contrast.js +2 -0
  3. package/dist/commands/auth/auth.js +61 -0
  4. package/dist/commands/config/config.js +24 -0
  5. package/dist/commands/scan/processScan.js +23 -0
  6. package/dist/common/HTTPClient.js +192 -0
  7. package/dist/common/errorHandling.js +60 -0
  8. package/dist/constants/constants.js +30 -0
  9. package/dist/constants/lambda.js +31 -0
  10. package/dist/constants/locales.js +259 -0
  11. package/dist/constants.js +150 -0
  12. package/dist/index.js +56 -0
  13. package/dist/lambda/__mocks__/aws.js +21 -0
  14. package/dist/lambda/__mocks__/lambdaConfig.json +42 -0
  15. package/dist/lambda/arn.js +21 -0
  16. package/dist/lambda/aws.js +169 -0
  17. package/dist/lambda/cliError.js +76 -0
  18. package/dist/lambda/constants.js +11 -0
  19. package/dist/lambda/help.js +75 -0
  20. package/dist/lambda/lambda.js +130 -0
  21. package/dist/lambda/logUtils.js +36 -0
  22. package/dist/lambda/scanDetail.js +30 -0
  23. package/dist/lambda/scanDetailCompletion.js +56 -0
  24. package/dist/lambda/scanRequest.js +93 -0
  25. package/dist/lambda/scanResults.js +16 -0
  26. package/dist/lambda/utils.js +90 -0
  27. package/dist/scan/autoDetection.js +76 -0
  28. package/dist/scan/fileFinder.js +15 -0
  29. package/dist/scan/fileUtils.js +31 -0
  30. package/dist/scan/help.js +68 -0
  31. package/dist/scan/populateProjectIdAndProjectName.js +55 -0
  32. package/dist/scan/scan.js +96 -0
  33. package/dist/scan/scanController.js +54 -0
  34. package/dist/scan/scanResults.js +85 -0
  35. package/dist/utils/commonApi.js +45 -0
  36. package/dist/utils/filterProjectPath.js +20 -0
  37. package/dist/utils/getConfig.js +30 -0
  38. package/dist/utils/oraWrapper.js +20 -0
  39. package/dist/utils/paramsUtil/commandlineParams.js +31 -0
  40. package/dist/utils/paramsUtil/configStoreParams.js +18 -0
  41. package/dist/utils/paramsUtil/envVariableParams.js +10 -0
  42. package/dist/utils/paramsUtil/paramHandler.js +28 -0
  43. package/dist/utils/paramsUtil/yamlParams.js +6 -0
  44. package/dist/utils/parsedCLIOptions.js +13 -0
  45. package/dist/utils/requestUtils.js +18 -0
  46. package/dist/utils/validationCheck.js +26 -0
  47. package/package.json +123 -0
  48. package/src/commands/auth/auth.js +73 -0
  49. package/src/commands/config/config.js +25 -0
  50. package/src/commands/scan/processScan.js +29 -0
  51. package/src/common/HTTPClient.js +269 -0
  52. package/src/common/errorHandling.ts +79 -0
  53. package/src/constants/constants.js +34 -0
  54. package/src/constants/lambda.js +41 -0
  55. package/src/constants/locales.js +381 -0
  56. package/src/constants.js +168 -0
  57. package/src/index.ts +69 -0
  58. package/src/lambda/__mocks__/aws.ts +32 -0
  59. package/src/lambda/__mocks__/lambdaConfig.json +42 -0
  60. package/src/lambda/arn.ts +32 -0
  61. package/src/lambda/aws.ts +247 -0
  62. package/src/lambda/cliError.ts +72 -0
  63. package/src/lambda/constants.ts +11 -0
  64. package/src/lambda/help.ts +76 -0
  65. package/src/lambda/lambda.ts +174 -0
  66. package/src/lambda/logUtils.ts +46 -0
  67. package/src/lambda/scanDetailCompletion.ts +78 -0
  68. package/src/lambda/scanRequest.ts +142 -0
  69. package/src/lambda/scanResults.ts +29 -0
  70. package/src/lambda/utils.ts +125 -0
  71. package/src/scan/autoDetection.js +77 -0
  72. package/src/scan/fileUtils.js +33 -0
  73. package/src/scan/help.js +74 -0
  74. package/src/scan/populateProjectIdAndProjectName.js +62 -0
  75. package/src/scan/scan.js +126 -0
  76. package/src/scan/scanController.js +69 -0
  77. package/src/scan/scanResults.js +96 -0
  78. package/src/utils/commonApi.js +54 -0
  79. package/src/utils/filterProjectPath.js +21 -0
  80. package/src/utils/getConfig.ts +42 -0
  81. package/src/utils/oraWrapper.js +24 -0
  82. package/src/utils/paramsUtil/commandlineParams.js +37 -0
  83. package/src/utils/paramsUtil/configStoreParams.js +19 -0
  84. package/src/utils/paramsUtil/envVariableParams.js +10 -0
  85. package/src/utils/paramsUtil/paramHandler.js +28 -0
  86. package/src/utils/parsedCLIOptions.js +17 -0
  87. package/src/utils/requestUtils.js +22 -0
  88. package/src/utils/validationCheck.js +34 -0
@@ -0,0 +1,78 @@
1
+ import { sleep } from '../utils/requestUtils'
2
+ import { getHttpClient } from '../utils/commonApi'
3
+ import { ApiParams } from './lambda'
4
+ import HTTPClient from '../common/HTTPClient'
5
+ import ora from '../utils/oraWrapper'
6
+ import { CliError } from './cliError'
7
+ import { ERRORS } from './constants'
8
+ import { ContrastConf } from '../utils/getConfig'
9
+
10
+ const MS_IN_MINUTE = 1000 * 60
11
+
12
+ const getScanResources = async (
13
+ config: ContrastConf,
14
+ params: ApiParams,
15
+ scanId: string,
16
+ httpClient: HTTPClient
17
+ ) => {
18
+ const res = await httpClient.getScanResources(config, params, scanId)
19
+ const { statusCode, body } = res
20
+
21
+ if (statusCode === 200) {
22
+ return res
23
+ }
24
+
25
+ const { errorCode } = body || {}
26
+ throw new CliError(ERRORS.FAILED_TO_GET_SCAN, { statusCode, errorCode })
27
+ }
28
+
29
+ const pollScanUntilCompletion = async (
30
+ config: any,
31
+ timeoutInMinutes: number,
32
+ params: ApiParams,
33
+ scanId: string
34
+ ) => {
35
+ const client = getHttpClient(config)
36
+
37
+ const activeStatuses = ['PENDING', 'SCANNING', 'QUEUED']
38
+ const startedText = 'Scan started'
39
+ const maxEndTime = new Date().getTime() + timeoutInMinutes * MS_IN_MINUTE
40
+ const startScanSpinner = ora.returnOra(startedText)
41
+ ora.startSpinner(startScanSpinner)
42
+
43
+ await sleep(5000) // wait 5 sec before first polling
44
+
45
+ let complete = false
46
+ while (!complete) {
47
+ try {
48
+ const result = await exports.getScanResources(
49
+ config,
50
+ params,
51
+ scanId,
52
+ client
53
+ )
54
+ const { resources: scans } = result.body.data
55
+ const staticScans = scans?.filter((s: any) => s.scanType === 2)
56
+ complete = staticScans.some((s: any) => !activeStatuses.includes(s.state))
57
+
58
+ if (complete) {
59
+ ora.succeedSpinner(startScanSpinner, 'Scan Finished')
60
+ return scans
61
+ }
62
+
63
+ await sleep(2 * 1000)
64
+ } catch (error) {
65
+ ora.failSpinner(startScanSpinner, 'Scan Failed')
66
+ throw error
67
+ }
68
+
69
+ if (Date.now() >= maxEndTime) {
70
+ ora.failSpinner(startScanSpinner, 'Scan timed out')
71
+ throw new CliError(ERRORS.FAILED_TO_GET_SCAN, {
72
+ errorCode: 'waitingTimedOut'
73
+ })
74
+ }
75
+ }
76
+ }
77
+
78
+ export { pollScanUntilCompletion, getScanResources }
@@ -0,0 +1,142 @@
1
+ import i18n from 'i18n'
2
+ import logSymbols from 'log-symbols'
3
+ import chalk from 'chalk'
4
+ import { parseARN } from './arn'
5
+ import {
6
+ getLambdaClient,
7
+ getLambdaFunctionConfiguration,
8
+ getLambdaPolicies,
9
+ getLayersLinks
10
+ } from './aws'
11
+ import { toLowerKeys } from './utils'
12
+ import { getHttpClient } from '../utils/commonApi'
13
+ import { ApiParams, LambdaOptions } from './lambda'
14
+ import { log, prettyPrintJson } from './logUtils'
15
+ import { CliError } from './cliError'
16
+ import { ERRORS } from './constants'
17
+
18
+ const sendScanPostRequest = async (
19
+ config: any,
20
+ params: ApiParams,
21
+ functionsEvent: unknown,
22
+ showProgress = false
23
+ ) => {
24
+ const client = getHttpClient(config)
25
+
26
+ if (showProgress) {
27
+ // prettier-ignore
28
+ log(`${logSymbols.success} Sending Lambda Function scan request to Contrast`)
29
+ }
30
+
31
+ const res = await client.postFunctionScan(config, params, functionsEvent)
32
+ const { statusCode, body } = res
33
+
34
+ if (statusCode === 201) {
35
+ if (showProgress) {
36
+ log(`${logSymbols.success} Scan requested successfully`)
37
+ }
38
+
39
+ return body?.data?.scanId
40
+ }
41
+
42
+ let { errorCode } = body?.data || {}
43
+ const { data } = body?.data || {}
44
+
45
+ let description = ''
46
+ switch (errorCode) {
47
+ case 'not_supported_runtime':
48
+ description = i18n.__(
49
+ errorCode,
50
+ data?.runtime,
51
+ data?.supportedRuntimes.sort().join(' | ')
52
+ )
53
+ errorCode = false
54
+ break
55
+ }
56
+
57
+ throw new CliError(ERRORS.FAILED_TO_START_SCAN, {
58
+ statusCode,
59
+ errorCode,
60
+ data,
61
+ description
62
+ })
63
+ }
64
+
65
+ const createFunctionEvent = (
66
+ lambdaConfig: any,
67
+ layersLinks: any,
68
+ lambdaPolicies: any
69
+ ) => {
70
+ delete lambdaConfig.$metadata
71
+
72
+ const functionEvent = toLowerKeys(lambdaConfig.Configuration)
73
+ functionEvent['code'] = lambdaConfig.Code
74
+ functionEvent['rolePolicies'] = lambdaPolicies
75
+
76
+ if (layersLinks) {
77
+ functionEvent['layers'] = layersLinks
78
+ }
79
+
80
+ return { function: functionEvent }
81
+ }
82
+
83
+ const requestScanFunctionPost = async (
84
+ config: any,
85
+ lambdaOptions: LambdaOptions
86
+ ) => {
87
+ const { verbose, jsonOutput, functionName } = lambdaOptions
88
+ const lambdaClient = getLambdaClient(lambdaOptions)
89
+
90
+ if (!jsonOutput) {
91
+ // prettier-ignore
92
+ log(`${logSymbols.success} Fetching configuration and policies for Lambda Function ${chalk.bold(functionName)}`)
93
+ }
94
+
95
+ const lambdaConfig = await getLambdaFunctionConfiguration(
96
+ lambdaClient,
97
+ lambdaOptions
98
+ )
99
+ if (!lambdaConfig?.Configuration) {
100
+ throw new CliError(ERRORS.FAILED_TO_START_SCAN, {
101
+ errorCode: 'missingLambdaConfig'
102
+ })
103
+ }
104
+ const { Configuration } = lambdaConfig
105
+ const layersLinks = await getLayersLinks(lambdaClient, Configuration)
106
+ const lambdaPolicies = await getLambdaPolicies(Configuration, lambdaOptions)
107
+
108
+ const functionEvent = createFunctionEvent(
109
+ lambdaConfig,
110
+ layersLinks,
111
+ lambdaPolicies
112
+ )
113
+ const { FunctionArn: functionArn } = Configuration
114
+ if (!functionArn) {
115
+ throw new CliError(ERRORS.FAILED_TO_START_SCAN, {
116
+ errorCode: 'missingLambdaArn'
117
+ })
118
+ }
119
+
120
+ const parsedARN = parseARN(functionArn)
121
+ const params: ApiParams = {
122
+ organizationId: config.organizationId,
123
+ provider: 'aws',
124
+ accountId: parsedARN.accountId
125
+ }
126
+
127
+ if (verbose) {
128
+ log(`${logSymbols.success} Fetched configuration from AWS:`)
129
+ prettyPrintJson(functionEvent)
130
+ }
131
+
132
+ const scanId = await sendScanPostRequest(
133
+ config,
134
+ params,
135
+ functionEvent,
136
+ !jsonOutput
137
+ )
138
+
139
+ return { scanId, params, functionArn }
140
+ }
141
+
142
+ export { sendScanPostRequest, requestScanFunctionPost, createFunctionEvent }
@@ -0,0 +1,29 @@
1
+ import { getHttpClient } from '../utils/commonApi'
2
+ import { CliError } from './cliError'
3
+ import { ERRORS } from './constants'
4
+ import { ApiParams } from './lambda'
5
+
6
+ const getScanResults = async (
7
+ config: any,
8
+ params: ApiParams,
9
+ scanId: string,
10
+ functionArn: string
11
+ ) => {
12
+ const client = getHttpClient(config)
13
+
14
+ const { statusCode, body } = await client.getFunctionScanResults(
15
+ config,
16
+ params,
17
+ scanId,
18
+ functionArn
19
+ )
20
+
21
+ if (statusCode === 200) {
22
+ return body
23
+ }
24
+
25
+ const { errorCode } = body || {}
26
+ throw new CliError(ERRORS.FAILED_TO_GET_RESULTS, { statusCode, errorCode })
27
+ }
28
+
29
+ export { getScanResults }
@@ -0,0 +1,125 @@
1
+ import chalk from 'chalk'
2
+ import { capitalize, groupBy, minBy, sortBy } from 'lodash'
3
+ import { log } from './logUtils'
4
+
5
+ const groupByCVE = ({ title }: any) =>
6
+ title.substring(0, title.indexOf('[') - 1)
7
+
8
+ const groupByDependency = ({ title }: any) =>
9
+ title.substring(title.indexOf('[') + 1, title.indexOf(']'))
10
+
11
+ const prettyPrintResults = (results: any[]) => {
12
+ log('')
13
+
14
+ //filter out any vulnerabs which is not least privilege or dependencies- cli does not handle other vulnerabs yet
15
+ const vulnerabs = results.filter(r => r.category === 1 || r.category === 4)
16
+ const sortBySeverity = sortBy(vulnerabs, ['severity', 'title'])
17
+ const notDependencies = sortBySeverity.filter(r => r.category !== 1)
18
+ const dependencies = sortBySeverity.filter(r => r.category === 1)
19
+ const dependenciesByLibrary = groupBy(dependencies, groupByDependency)
20
+ const dependenciesCount = Object.keys(dependenciesByLibrary).length
21
+
22
+ notDependencies.forEach(printVulnerability)
23
+
24
+ const prevIndex = notDependencies.length + 1
25
+ Object.entries(dependenciesByLibrary).forEach(([library, group], i) => {
26
+ const maxSeverity = minBy(group, 'severity')
27
+ const allCves = group.map(groupByCVE)
28
+
29
+ log(prevIndex + i)
30
+ log(
31
+ `${chalk.bold(capitalize(maxSeverity.severityText))} | ${chalk.bold(
32
+ 'Vulnerable dependency'
33
+ )} ${library} has ${group.length} known CVEs`
34
+ )
35
+ log(allCves.join(', '))
36
+ if (maxSeverity.remediation?.description) {
37
+ log(
38
+ `${chalk.bold('Recommendation:')} ${
39
+ maxSeverity.remediation.description
40
+ }`
41
+ )
42
+ }
43
+ log('')
44
+ })
45
+
46
+ const resultCount = notDependencies.length + dependenciesCount
47
+ const groupByType = groupBy(notDependencies, ['categoryText'])
48
+ const summary = Object.values(groupByType).map(
49
+ group => `${group.length} ${capitalize(group[0].categoryText)}`
50
+ )
51
+ log(`Found ${resultCount} vulnerabilities`, { bold: true })
52
+ summary.push(`${dependenciesCount} Dependencies`)
53
+
54
+ log(chalk.bold(summary.join(' | ')))
55
+ }
56
+
57
+ const underlineLinks = (text: string) => {
58
+ if (!text) {
59
+ return text
60
+ }
61
+
62
+ const urlRegex = /(https?:\/\/[^\s]+)/g
63
+ return text.replace(urlRegex, chalk.underline('$1'))
64
+ }
65
+
66
+ const printVulnerability = (vulnerability: any, index: number) => {
67
+ log(index + 1)
68
+ const descriptionWithLinks = underlineLinks(vulnerability.description)
69
+ log(
70
+ `${chalk.bold(capitalize(vulnerability.severityText))} | ${chalk.bold(
71
+ vulnerability.title
72
+ )} ${descriptionWithLinks}`
73
+ )
74
+
75
+ const category = vulnerability?.categoryText
76
+ switch (category) {
77
+ case 'PERMISSIONS':
78
+ printLeastPrivilegeRemediation(vulnerability)
79
+ break
80
+ default:
81
+ printRemediation(vulnerability)
82
+ }
83
+ log('')
84
+ }
85
+
86
+ const printLeastPrivilegeRemediation = (vulnerability: any) => {
87
+ log(
88
+ `${chalk.bold(
89
+ 'Recommendation:'
90
+ )} Replace the existing policies with the following`
91
+ )
92
+
93
+ const violatingPolicies =
94
+ vulnerability?.evidence?.leastPrivilege?.violatingPolicies || []
95
+
96
+ violatingPolicies
97
+ .filter((vp: any) => vp?.suggestedPolicy?.suggestedPolicyCode?.length)
98
+ .map((vp: any) => vp?.suggestedPolicy?.suggestedPolicyCode)
99
+ .forEach((policies: any) => {
100
+ policies.forEach((policy: any) => {
101
+ console.log(policy.snippet)
102
+ })
103
+ })
104
+ }
105
+
106
+ const printRemediation = (vulnerability: any) => {
107
+ log(`Remediation - ${vulnerability?.remediation?.description || 'Unknown'}`)
108
+ }
109
+
110
+ function toLowerKeys(obj: Record<string, unknown>) {
111
+ return Object.keys(obj).reduce((accumulator, key) => {
112
+ const new_key = `${key[0].toLowerCase()}${key.slice(1)}`
113
+ accumulator[new_key] = obj[key]
114
+ return accumulator
115
+ }, {} as Record<string, unknown>)
116
+ }
117
+
118
+ export { toLowerKeys, prettyPrintResults }
119
+
120
+ export const exportedForTesting = {
121
+ printLeastPrivilegeRemediation,
122
+ printRemediation,
123
+ printVulnerability,
124
+ underlineLinks
125
+ }
@@ -0,0 +1,77 @@
1
+ const i18n = require('i18n')
2
+ const { zipValidator } = require('./scan')
3
+ const fileFinder = require('./fileUtils')
4
+ const { supportedLanguages } = require('../constants/constants')
5
+
6
+ const autoDetectFileAndLanguage = async configToUse => {
7
+ const entries = await fileFinder.findFile()
8
+
9
+ if (entries.length === 1) {
10
+ console.log(i18n.__('foundScanFile', entries[0]))
11
+
12
+ if (hasWhiteSpace(entries[0])) {
13
+ console.log(i18n.__('fileHasWhiteSpacesError'))
14
+ process.exit(1)
15
+ }
16
+
17
+ configToUse.file = entries[0]
18
+ if (configToUse.name === undefined) {
19
+ configToUse.name = entries[0]
20
+ }
21
+ zipValidator(configToUse)
22
+ assignLanguage(entries, configToUse)
23
+ } else {
24
+ errorOnFileDetection(entries)
25
+ }
26
+ }
27
+
28
+ const hasWhiteSpace = s => {
29
+ const filename = s.split('/').pop()
30
+ return filename.indexOf(' ') >= 0
31
+ }
32
+
33
+ const errorOnFileDetection = entries => {
34
+ if (entries.length > 1) {
35
+ console.log(i18n.__('searchingDirectoryScan'))
36
+ for (let file in entries) {
37
+ console.log('-', entries[file])
38
+ }
39
+ console.log('')
40
+ console.log(i18n.__('specifyFileScanError'))
41
+ } else {
42
+ console.log(i18n.__('noFileFoundScan'))
43
+ console.log('')
44
+ console.log(i18n.__('specifyFileScanError'))
45
+ }
46
+ process.exit(1)
47
+ }
48
+
49
+ const assignLanguage = (entries, configToUse) => {
50
+ let split = entries[0].split('.')
51
+ const fileType = split[split.length - 1]
52
+ if (fileType === 'war' || fileType === 'jar') {
53
+ console.log('Language is Java')
54
+ configToUse.language = 'JAVA'
55
+ } else if (fileType === 'dll') {
56
+ console.log('Language is Dotnet')
57
+ configToUse.language = 'DOTNET'
58
+ } else if (fileType === 'js') {
59
+ console.log('Language is Javascript')
60
+ configToUse.language = supportedLanguages.JAVASCRIPT
61
+ } else if (fileType === 'zip') {
62
+ if (configToUse.language !== supportedLanguages.JAVASCRIPT) {
63
+ console.log(i18n.__('zipErrorScan'))
64
+ process.exit(1)
65
+ }
66
+ console.log('Language is Javascript within zip file')
67
+ } else {
68
+ console.log(i18n.__('unknownFileErrorScan'))
69
+ process.exit(1)
70
+ }
71
+ }
72
+
73
+ module.exports = {
74
+ autoDetectFileAndLanguage,
75
+ assignLanguage,
76
+ errorOnFileDetection
77
+ }
@@ -0,0 +1,33 @@
1
+ const fg = require('fast-glob')
2
+ const fs = require('fs')
3
+ const i18n = require('i18n')
4
+
5
+ const findFile = async () => {
6
+ console.log(i18n.__('searchingScanFileDirectory', process.cwd()))
7
+ return fg(['**/*.jar', '**/*.war', '**/*.zip', '**/*.dll'], {
8
+ dot: false,
9
+ deep: 3,
10
+ onlyFiles: true
11
+ })
12
+ }
13
+
14
+ const checkFilePermissions = file => {
15
+ let readableFile = false
16
+ try {
17
+ fs.accessSync(file, fs.constants.R_OK)
18
+ return (readableFile = true) // testing purposes
19
+ } catch (err) {
20
+ console.log('Invalid permissions found on ', file)
21
+ process.exit(0)
22
+ }
23
+ }
24
+
25
+ const fileExists = path => {
26
+ return fs.existsSync(path)
27
+ }
28
+
29
+ module.exports = {
30
+ findFile,
31
+ fileExists,
32
+ checkFilePermissions
33
+ }
@@ -0,0 +1,74 @@
1
+ const commandLineUsage = require('command-line-usage')
2
+ const i18n = require('i18n')
3
+
4
+ const scanUsageGuide = commandLineUsage([
5
+ {
6
+ header: i18n.__('scanHeader')
7
+ },
8
+ {
9
+ header: i18n.__('constantsPrerequisitesHeader'),
10
+ content: [
11
+ '{bold ' + i18n.__('constantsPrerequisitesContentScanLanguages') + '}',
12
+ i18n.__('constantsPrerequisitesContent'),
13
+ '',
14
+ i18n.__('constantsUsageCommandInfo'),
15
+ i18n.__('constantsUsageCommandInfo24Hours')
16
+ ]
17
+ },
18
+ {
19
+ header: i18n.__('constantsScanOptions'),
20
+ content: [
21
+ {
22
+ name: i18n.__('scanOptionsFileName'),
23
+ summary:
24
+ '{italic ' +
25
+ i18n.__('constantsOptional') +
26
+ '}: ' +
27
+ i18n.__('scanOptionsFileNameSummary')
28
+ },
29
+ {
30
+ name: i18n.__('scanOptionsLanguage'),
31
+ summary:
32
+ '{italic ' +
33
+ i18n.__('constantsOptional') +
34
+ '}: ' +
35
+ i18n.__('scanOptionsLanguageSummaryOptional') +
36
+ '{italic ' +
37
+ i18n.__('constantsRequired') +
38
+ '}: ' +
39
+ i18n.__('scanOptionsLanguageSummaryRequired')
40
+ },
41
+ {
42
+ name: i18n.__('scanOptionsName'),
43
+ summary:
44
+ '{italic ' +
45
+ i18n.__('constantsOptional') +
46
+ '}: ' +
47
+ i18n.__('scanOptionsNameSummary')
48
+ },
49
+ {
50
+ name: i18n.__('scanOptionsTimeout'),
51
+ summary:
52
+ '{italic ' +
53
+ i18n.__('constantsOptional') +
54
+ '}: ' +
55
+ i18n.__('scanOptionsTimeoutSummary')
56
+ },
57
+ {
58
+ name: i18n.__('scanOptionsVerbose'),
59
+ summary:
60
+ '{italic ' +
61
+ i18n.__('constantsOptional') +
62
+ '}: ' +
63
+ i18n.__('scanOptionsVerboseSummary')
64
+ }
65
+ ]
66
+ },
67
+ {
68
+ content: '{underline https://www.contrastsecurity.com}'
69
+ }
70
+ ])
71
+
72
+ module.exports = {
73
+ scanUsageGuide
74
+ }
@@ -0,0 +1,62 @@
1
+ const commonApi = require('../utils/commonApi.js')
2
+ const i18n = require('i18n')
3
+
4
+ const populateProjectId = async config => {
5
+ const client = commonApi.getHttpClient(config)
6
+ let proj = await createProjectId(config, client)
7
+ if (proj === undefined) {
8
+ proj = await getExistingProjectIdByName(config, client).then(res => {
9
+ return res
10
+ })
11
+ }
12
+
13
+ return proj
14
+ }
15
+
16
+ const createProjectId = async (config, client) => {
17
+ return client
18
+ .createProjectId(config)
19
+ .then(res => {
20
+ if (res.statusCode === 409) {
21
+ console.log(i18n.__('foundExistingProjectScan'))
22
+ return
23
+ }
24
+
25
+ if (res.statusCode === 201) {
26
+ console.log(i18n.__('projectCreatedScan'))
27
+ if (config.verbose) {
28
+ console.log(i18n.__('populateProjectIdMessage', res.body.id))
29
+ }
30
+ return res.body.id
31
+ }
32
+ })
33
+ .catch(err => {
34
+ if (config.verbose) {
35
+ console.log(err)
36
+ }
37
+ console.log(i18n.__('connectionError'))
38
+ process.exit(0)
39
+ })
40
+ }
41
+
42
+ const getExistingProjectIdByName = async (config, client) => {
43
+ return client
44
+ .getProjectIdByName(config)
45
+ .then(res => {
46
+ if (res.statusCode === 200) {
47
+ if (config.verbose) {
48
+ console.log(
49
+ i18n.__('populateProjectIdMessage', res.body.content[0].id)
50
+ )
51
+ }
52
+ return res.body.content[0].id
53
+ }
54
+ })
55
+ .catch(err => {
56
+ console.log(err)
57
+ })
58
+ }
59
+
60
+ module.exports = {
61
+ populateProjectId: populateProjectId
62
+ }