@contrast/contrast 1.0.20 → 1.0.22
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/dist/cliConstants.js +17 -9
- package/dist/commands/audit/help.js +5 -1
- package/dist/commands/audit/processAudit.js +1 -1
- package/dist/commands/auth/auth.js +5 -0
- package/dist/commands/fingerprint/fingerprintConfig.js +12 -0
- package/dist/commands/fingerprint/processFingerprint.js +14 -0
- package/dist/commands/learn/learn.js +9 -0
- package/dist/commands/learn/processLearn.js +10 -0
- package/dist/common/HTTPClient.js +9 -0
- package/dist/common/commonHelp.js +8 -1
- package/dist/constants/constants.js +1 -1
- package/dist/constants/lambda.js +1 -0
- package/dist/constants/locales.js +20 -12
- package/dist/index.js +8 -0
- package/dist/lambda/help.js +5 -1
- package/dist/lambda/scanRequest.js +12 -1
- package/dist/scaAnalysis/common/treeUpload.js +3 -0
- package/dist/scaAnalysis/javascript/analysis.js +11 -33
- package/dist/scaAnalysis/javascript/index.js +14 -1
- package/dist/scaAnalysis/javascript/scaServiceParser.js +3 -3
- package/dist/scaAnalysis/scaAnalysis.js +155 -0
- package/dist/scan/autoDetection.js +2 -2
- package/dist/scan/fileUtils.js +2 -2
- package/dist/scan/help.js +5 -1
- package/dist/utils/settingsHelper.js +2 -2
- package/package.json +1 -1
- package/src/cliConstants.js +19 -9
- package/src/commands/audit/help.js +5 -1
- package/src/commands/audit/processAudit.js +1 -1
- package/src/commands/auth/auth.js +5 -0
- package/src/commands/fingerprint/fingerprintConfig.js +19 -0
- package/src/commands/fingerprint/processFingerprint.js +21 -0
- package/src/commands/learn/learn.js +10 -0
- package/src/commands/learn/processLearn.js +13 -0
- package/src/common/HTTPClient.js +11 -0
- package/src/common/commonHelp.js +11 -1
- package/src/constants/constants.js +1 -1
- package/src/constants/lambda.js +1 -0
- package/src/constants/locales.js +28 -12
- package/src/index.ts +10 -0
- package/src/lambda/help.ts +5 -1
- package/src/lambda/scanRequest.ts +27 -2
- package/src/scaAnalysis/common/treeUpload.js +7 -0
- package/src/scaAnalysis/javascript/analysis.js +19 -34
- package/src/scaAnalysis/javascript/index.js +29 -1
- package/src/scaAnalysis/javascript/scaServiceParser.js +3 -3
- package/src/scaAnalysis/scaAnalysis.js +206 -0
- package/src/scan/autoDetection.js +2 -2
- package/src/scan/fileUtils.js +2 -2
- package/src/scan/help.js +5 -1
- package/src/utils/settingsHelper.js +2 -2
- package/dist/commands/scan/sca/scaAnalysis.js +0 -157
- package/src/commands/scan/sca/scaAnalysis.js +0 -211
|
@@ -14,12 +14,22 @@ import { ApiParams, LambdaOptions } from './lambda'
|
|
|
14
14
|
import { log, prettyPrintJson } from './logUtils'
|
|
15
15
|
import { CliError } from './cliError'
|
|
16
16
|
import { ERRORS } from './constants'
|
|
17
|
+
import { sleep } from '../utils/requestUtils'
|
|
17
18
|
|
|
18
|
-
const
|
|
19
|
+
const MAX_RETRIES = 2
|
|
20
|
+
|
|
21
|
+
const sendScanPostRequest: (
|
|
19
22
|
config: any,
|
|
20
23
|
params: ApiParams,
|
|
21
24
|
functionsEvent: unknown,
|
|
22
|
-
showProgress
|
|
25
|
+
showProgress?: boolean,
|
|
26
|
+
retryNumber?: number
|
|
27
|
+
) => any = async (
|
|
28
|
+
config,
|
|
29
|
+
params,
|
|
30
|
+
functionsEvent,
|
|
31
|
+
showProgress = false,
|
|
32
|
+
retryNumber = 0
|
|
23
33
|
) => {
|
|
24
34
|
const client = getHttpClient(config)
|
|
25
35
|
|
|
@@ -50,6 +60,21 @@ const sendScanPostRequest = async (
|
|
|
50
60
|
})
|
|
51
61
|
errorCode = false
|
|
52
62
|
break
|
|
63
|
+
case 'not_supported_lambda':
|
|
64
|
+
description = i18n.__(errorCode)
|
|
65
|
+
errorCode = false
|
|
66
|
+
break
|
|
67
|
+
default:
|
|
68
|
+
if (retryNumber < MAX_RETRIES) {
|
|
69
|
+
await sleep(3 * 1000)
|
|
70
|
+
return sendScanPostRequest(
|
|
71
|
+
config,
|
|
72
|
+
params,
|
|
73
|
+
functionsEvent,
|
|
74
|
+
showProgress,
|
|
75
|
+
retryNumber + 1
|
|
76
|
+
)
|
|
77
|
+
}
|
|
53
78
|
}
|
|
54
79
|
|
|
55
80
|
throw new CliError(ERRORS.FAILED_TO_START_SCAN, {
|
|
@@ -18,6 +18,13 @@ const commonSendSnapShot = async (analysis, config) => {
|
|
|
18
18
|
if (res.statusCode === 201) {
|
|
19
19
|
return res.body
|
|
20
20
|
} else {
|
|
21
|
+
if (res.statusCode === 403) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`🛑 Contrast audit failed \nPlease check you have the right permissions and the application ${
|
|
24
|
+
config.applicationName ? config.applicationName : ''
|
|
25
|
+
} has not been archived.`.replace(/ +(?= )/g, '')
|
|
26
|
+
)
|
|
27
|
+
}
|
|
21
28
|
throw new Error(res.statusCode + ` error processing dependencies`)
|
|
22
29
|
}
|
|
23
30
|
})
|
|
@@ -44,48 +44,33 @@ const readYarn = async (config, languageFiles, nameOfFile) => {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
const parseNpmLockFile = async
|
|
47
|
+
const parseNpmLockFile = async npmLockFile => {
|
|
48
48
|
try {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
Object.entries(js.npmLockFile.dependencies).forEach(([objKey, value]) => {
|
|
53
|
-
if (value.requires) {
|
|
54
|
-
const listOfRequiresDep = Object.keys(value.requires)
|
|
55
|
-
listOfRequiresDep.forEach(dep => {
|
|
56
|
-
if (!listOfTopDep.includes(dep)) {
|
|
57
|
-
addDepToLockFile(js, value['requires'], dep)
|
|
58
|
-
}
|
|
59
|
-
})
|
|
60
|
-
}
|
|
49
|
+
if (!npmLockFile.parsedPackages) {
|
|
50
|
+
npmLockFile.parsedPackages = {}
|
|
51
|
+
}
|
|
61
52
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (!listOfTopDep.includes(dep)) {
|
|
69
|
-
addDepToLockFile(js, childValue['requires'], dep)
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
)
|
|
53
|
+
Object.entries(npmLockFile.packages).forEach(
|
|
54
|
+
([packageKey, packageValue]) => {
|
|
55
|
+
if (packageKey.includes('node_modules/')) {
|
|
56
|
+
//remove object keys node modules prefixing
|
|
57
|
+
//e.g: node_modules/@aws-amplify/datastore/node_modules/uuid --> @aws-amplify/datastore/uuid
|
|
58
|
+
packageKey = packageKey.replace(/(node_modules\/)+/g, '')
|
|
75
59
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
60
|
+
|
|
61
|
+
npmLockFile.parsedPackages[packageKey] = packageValue
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
//remove base project package - unneeded
|
|
66
|
+
delete npmLockFile.parsedPackages['']
|
|
67
|
+
|
|
68
|
+
return npmLockFile
|
|
81
69
|
} catch (err) {
|
|
82
70
|
throw new Error(i18n.__('NodeParseNPM') + `${err.message}`)
|
|
83
71
|
}
|
|
84
72
|
}
|
|
85
73
|
|
|
86
|
-
const addDepToLockFile = (js, depObj, key) => {
|
|
87
|
-
return (js.npmLockFile.dependencies[key] = { version: depObj[key] })
|
|
88
|
-
}
|
|
89
74
|
const parseYarnLockFile = async js => {
|
|
90
75
|
try {
|
|
91
76
|
js.yarn.yarnLockFile = {}
|
|
@@ -14,9 +14,11 @@ const jsAnalysis = async (config, languageFiles) => {
|
|
|
14
14
|
const buildNodeTree = async (config, files) => {
|
|
15
15
|
let analysis = await readFiles(config, files)
|
|
16
16
|
const rawNode = await parseFiles(config, files, analysis)
|
|
17
|
+
|
|
17
18
|
if (config.experimental) {
|
|
18
19
|
return scaServiceParser.parseJS(rawNode)
|
|
19
20
|
}
|
|
21
|
+
|
|
20
22
|
return formatMessage.createJavaScriptTSMessage(rawNode)
|
|
21
23
|
}
|
|
22
24
|
|
|
@@ -44,8 +46,34 @@ const readFiles = async (config, files) => {
|
|
|
44
46
|
|
|
45
47
|
const parseFiles = async (config, files, js) => {
|
|
46
48
|
if (files.includes('package-lock.json')) {
|
|
47
|
-
|
|
49
|
+
const npmLockFile = JSON.parse(js.rawLockFileContents)
|
|
50
|
+
|
|
51
|
+
const currentLockFileVersion = npmLockFile.lockfileVersion
|
|
52
|
+
const generalRebuildMessage =
|
|
53
|
+
'\nPlease update to Node 16+ & NPM 8+ or 9+ and then rebuild your package files.' +
|
|
54
|
+
'\nMore info here: https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json'
|
|
55
|
+
|
|
56
|
+
if (currentLockFileVersion === 1) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`NPM lockfileVersion 1 is no longer supported. \n ${generalRebuildMessage}`
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!currentLockFileVersion || !npmLockFile.packages) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`package-lock.json needs to be in the NPM v2 or v3 format. \n ${generalRebuildMessage}`
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (currentLockFileVersion === 3 && !config.experimental) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`NPM lockfileVersion 3 is only supported when using the '-e' flag.`
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
js.npmLockFile = await analysis.parseNpmLockFile(npmLockFile)
|
|
48
75
|
}
|
|
76
|
+
|
|
49
77
|
if (files.includes('yarn.lock')) {
|
|
50
78
|
js = await analysis.parseYarnLockFile(js)
|
|
51
79
|
}
|
|
@@ -77,7 +77,7 @@ const chooseLockFile = rawNode => {
|
|
|
77
77
|
if (rawNode?.yarn?.yarnLockFile !== undefined) {
|
|
78
78
|
return { lockFile: rawNode?.yarn?.yarnLockFile?.object, type: 'yarn' }
|
|
79
79
|
} else if (rawNode.npmLockFile !== undefined) {
|
|
80
|
-
return { lockFile: rawNode?.npmLockFile?.
|
|
80
|
+
return { lockFile: rawNode?.npmLockFile?.parsedPackages, type: 'npm' }
|
|
81
81
|
} else {
|
|
82
82
|
return undefined
|
|
83
83
|
}
|
|
@@ -105,9 +105,9 @@ const createChildDependencies = (lockFileDep, currentDep) => {
|
|
|
105
105
|
|
|
106
106
|
const createNPMChildDependencies = (lockFileDep, currentDep) => {
|
|
107
107
|
let depArray = []
|
|
108
|
-
if (lockFileDep[currentDep]?.
|
|
108
|
+
if (lockFileDep[currentDep]?.dependencies) {
|
|
109
109
|
for (const [key, value] of Object.entries(
|
|
110
|
-
lockFileDep[currentDep]?.
|
|
110
|
+
lockFileDep[currentDep]?.dependencies
|
|
111
111
|
)) {
|
|
112
112
|
depArray.push(key)
|
|
113
113
|
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
const {
|
|
2
|
+
supportedLanguages: { JAVA, GO, PYTHON, RUBY, JAVASCRIPT, NODE, PHP, DOTNET }
|
|
3
|
+
} = require('../constants/constants')
|
|
4
|
+
const {
|
|
5
|
+
pollForSnapshotCompletion
|
|
6
|
+
} = require('../audit/languageAnalysisEngine/sendSnapshot')
|
|
7
|
+
const {
|
|
8
|
+
returnOra,
|
|
9
|
+
startSpinner,
|
|
10
|
+
succeedSpinner
|
|
11
|
+
} = require('../utils/oraWrapper')
|
|
12
|
+
const { vulnerabilityReportV2 } = require('../audit/report/reportingFeature')
|
|
13
|
+
const autoDetection = require('../scan/autoDetection')
|
|
14
|
+
const treeUpload = require('./common/treeUpload')
|
|
15
|
+
const auditController = require('../commands/audit/auditController')
|
|
16
|
+
const rootFile = require('../audit/languageAnalysisEngine/getProjectRootFilenames')
|
|
17
|
+
const path = require('path')
|
|
18
|
+
const i18n = require('i18n')
|
|
19
|
+
const auditSave = require('../audit/save')
|
|
20
|
+
const { auditUsageGuide } = require('../commands/audit/help')
|
|
21
|
+
const repoMode = require('./repoMode')
|
|
22
|
+
const { dotNetAnalysis } = require('./dotnet')
|
|
23
|
+
const { goAnalysis } = require('./go/goAnalysis')
|
|
24
|
+
const { phpAnalysis } = require('./php')
|
|
25
|
+
const { rubyAnalysis } = require('./ruby')
|
|
26
|
+
const { pythonAnalysis } = require('./python')
|
|
27
|
+
const javaAnalysis = require('./java')
|
|
28
|
+
const jsAnalysis = require('./javascript')
|
|
29
|
+
const auditReport = require('./common/auditReport')
|
|
30
|
+
const scaUpload = require('./common/scaServicesUpload')
|
|
31
|
+
const settingsHelper = require('../utils/settingsHelper')
|
|
32
|
+
const chalk = require('chalk')
|
|
33
|
+
const saveResults = require('../scan/saveResults')
|
|
34
|
+
const {
|
|
35
|
+
convertGenericToTypedReportModelSca
|
|
36
|
+
} = require('./common/utils/reportUtilsSca')
|
|
37
|
+
|
|
38
|
+
const processSca = async config => {
|
|
39
|
+
//checks to see whether to use old TS / new SCA path
|
|
40
|
+
config = await settingsHelper.getSettings(config)
|
|
41
|
+
|
|
42
|
+
const startTime = performance.now()
|
|
43
|
+
let filesFound
|
|
44
|
+
|
|
45
|
+
if (config.help) {
|
|
46
|
+
console.log(auditUsageGuide)
|
|
47
|
+
process.exit(0)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const projectStats = await rootFile.getProjectStats(config.file)
|
|
51
|
+
let pathWithFile = projectStats.isFile()
|
|
52
|
+
|
|
53
|
+
config.fileName = config.file
|
|
54
|
+
config.file = pathWithFile
|
|
55
|
+
? rootFile.getDirectoryFromPathGiven(config.file).concat('/')
|
|
56
|
+
: config.file
|
|
57
|
+
|
|
58
|
+
filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config.file)
|
|
59
|
+
|
|
60
|
+
autoDetection.dealWithMultiJava(filesFound)
|
|
61
|
+
|
|
62
|
+
if (filesFound.length > 1 && pathWithFile) {
|
|
63
|
+
filesFound = filesFound.filter(i =>
|
|
64
|
+
Object.values(i)[0].includes(path.basename(config.fileName))
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// files found looks like [ { javascript: [ Array ] } ]
|
|
69
|
+
//check we have the language and call the right analyser
|
|
70
|
+
let messageToSend = undefined
|
|
71
|
+
if (filesFound.length === 1) {
|
|
72
|
+
switch (Object.keys(filesFound[0])[0]) {
|
|
73
|
+
case JAVA:
|
|
74
|
+
config.language = JAVA
|
|
75
|
+
|
|
76
|
+
if (config.mode === 'repo') {
|
|
77
|
+
try {
|
|
78
|
+
return repoMode.buildRepo(config, filesFound[0])
|
|
79
|
+
} catch (e) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
'Unable to build in repository mode. Check your project file'
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
messageToSend = await javaAnalysis.javaAnalysis(config, filesFound[0])
|
|
86
|
+
}
|
|
87
|
+
break
|
|
88
|
+
case JAVASCRIPT:
|
|
89
|
+
messageToSend = await jsAnalysis.jsAnalysis(config, filesFound[0])
|
|
90
|
+
config.language = NODE
|
|
91
|
+
break
|
|
92
|
+
case PYTHON:
|
|
93
|
+
messageToSend = pythonAnalysis(config, filesFound[0])
|
|
94
|
+
config.language = PYTHON
|
|
95
|
+
break
|
|
96
|
+
case RUBY:
|
|
97
|
+
messageToSend = rubyAnalysis(config, filesFound[0])
|
|
98
|
+
config.language = RUBY
|
|
99
|
+
break
|
|
100
|
+
case PHP:
|
|
101
|
+
messageToSend = phpAnalysis(config, filesFound[0])
|
|
102
|
+
config.language = PHP
|
|
103
|
+
break
|
|
104
|
+
case GO:
|
|
105
|
+
messageToSend = goAnalysis(config, filesFound[0])
|
|
106
|
+
config.language = GO
|
|
107
|
+
break
|
|
108
|
+
case DOTNET:
|
|
109
|
+
if (config.experimental) {
|
|
110
|
+
console.log(
|
|
111
|
+
`${chalk.bold(
|
|
112
|
+
'\n.NET project found\n'
|
|
113
|
+
)} Language type is unsupported.`
|
|
114
|
+
)
|
|
115
|
+
return
|
|
116
|
+
} else {
|
|
117
|
+
messageToSend = dotNetAnalysis(config, filesFound[0])
|
|
118
|
+
config.language = DOTNET
|
|
119
|
+
break
|
|
120
|
+
}
|
|
121
|
+
default:
|
|
122
|
+
//something is wrong
|
|
123
|
+
console.log('No supported language detected in project path')
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!config.applicationId) {
|
|
128
|
+
config.applicationId = await auditController.dealWithNoAppId(config)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (config.experimental) {
|
|
132
|
+
console.log('') //empty log for space before spinner
|
|
133
|
+
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'))
|
|
134
|
+
startSpinner(reportSpinner)
|
|
135
|
+
const { reportArray, reportId } = await scaUpload.scaTreeUpload(
|
|
136
|
+
messageToSend,
|
|
137
|
+
config
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
const reportModelLibraryList =
|
|
141
|
+
convertGenericToTypedReportModelSca(reportArray)
|
|
142
|
+
auditReport.processAuditReport(config, reportModelLibraryList)
|
|
143
|
+
succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'))
|
|
144
|
+
|
|
145
|
+
if (config.save !== undefined) {
|
|
146
|
+
await auditSave.auditSave(config, reportId)
|
|
147
|
+
} else {
|
|
148
|
+
console.log('Use contrast audit --save to generate an SBOM')
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const endTime = performance.now() - startTime
|
|
152
|
+
const scanDurationMs = endTime - startTime
|
|
153
|
+
console.log(
|
|
154
|
+
`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`
|
|
155
|
+
)
|
|
156
|
+
} else {
|
|
157
|
+
console.log('') //empty log for space before spinner
|
|
158
|
+
//send message to TS
|
|
159
|
+
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'))
|
|
160
|
+
startSpinner(reportSpinner)
|
|
161
|
+
const snapshotResponse = await treeUpload.commonSendSnapShot(
|
|
162
|
+
messageToSend,
|
|
163
|
+
config
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
// poll for completion
|
|
167
|
+
await pollForSnapshotCompletion(
|
|
168
|
+
config,
|
|
169
|
+
snapshotResponse.id,
|
|
170
|
+
reportSpinner
|
|
171
|
+
)
|
|
172
|
+
succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'))
|
|
173
|
+
|
|
174
|
+
await vulnerabilityReportV2(config, snapshotResponse.id)
|
|
175
|
+
if (config.save !== undefined) {
|
|
176
|
+
await auditSave.auditSave(config)
|
|
177
|
+
} else {
|
|
178
|
+
console.log('\nUse contrast audit --save to generate an SBOM')
|
|
179
|
+
}
|
|
180
|
+
const endTime = performance.now() - startTime
|
|
181
|
+
const scanDurationMs = endTime - startTime
|
|
182
|
+
|
|
183
|
+
console.log(
|
|
184
|
+
`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
} else {
|
|
188
|
+
if (filesFound.length === 0) {
|
|
189
|
+
console.log(i18n.__('languageAnalysisNoLanguage'))
|
|
190
|
+
console.log(i18n.__('languageAnalysisNoLanguageHelpLine'))
|
|
191
|
+
throw new Error()
|
|
192
|
+
} else {
|
|
193
|
+
console.log(chalk.bold(`\nMultiple language files detected \n`))
|
|
194
|
+
filesFound.forEach(file => {
|
|
195
|
+
console.log(`${Object.keys(file)[0]} : `, Object.values(file)[0])
|
|
196
|
+
})
|
|
197
|
+
throw new Error(
|
|
198
|
+
`Please use --file to audit one language only. \nExample: contrast audit --file package-lock.json`
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
module.exports = {
|
|
205
|
+
processSca
|
|
206
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const i18n = require('i18n')
|
|
2
2
|
const fileFinder = require('./fileUtils')
|
|
3
3
|
|
|
4
|
-
const autoDetectFingerprintInfo = async filePath => {
|
|
5
|
-
let complexObj = await fileFinder.findAllFiles(filePath)
|
|
4
|
+
const autoDetectFingerprintInfo = async (filePath, depth) => {
|
|
5
|
+
let complexObj = await fileFinder.findAllFiles(filePath, depth)
|
|
6
6
|
let result = []
|
|
7
7
|
let count = 0
|
|
8
8
|
complexObj.forEach(i => {
|
package/src/scan/fileUtils.js
CHANGED
|
@@ -11,7 +11,7 @@ const findFile = async () => {
|
|
|
11
11
|
})
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
const findAllFiles = async filePath => {
|
|
14
|
+
const findAllFiles = async (filePath, depth = 2) => {
|
|
15
15
|
const result = await fg(
|
|
16
16
|
[
|
|
17
17
|
'**/pom.xml',
|
|
@@ -25,7 +25,7 @@ const findAllFiles = async filePath => {
|
|
|
25
25
|
],
|
|
26
26
|
{
|
|
27
27
|
dot: false,
|
|
28
|
-
deep:
|
|
28
|
+
deep: depth,
|
|
29
29
|
onlyFiles: true,
|
|
30
30
|
absolute: true,
|
|
31
31
|
cwd: filePath ? filePath : process.cwd()
|
package/src/scan/help.js
CHANGED
|
@@ -4,6 +4,9 @@ const constants = require('../cliConstants')
|
|
|
4
4
|
const { commonHelpLinks } = require('../common/commonHelp')
|
|
5
5
|
|
|
6
6
|
const scanUsageGuide = commandLineUsage([
|
|
7
|
+
{
|
|
8
|
+
header: i18n.__('constantsHeader')
|
|
9
|
+
},
|
|
7
10
|
{
|
|
8
11
|
header: i18n.__('scanHeader')
|
|
9
12
|
},
|
|
@@ -44,7 +47,8 @@ const scanUsageGuide = commandLineUsage([
|
|
|
44
47
|
constants.commandLineDefinitions.scanAdvancedOptionDefinitionsForHelp
|
|
45
48
|
},
|
|
46
49
|
commonHelpLinks()[0],
|
|
47
|
-
commonHelpLinks()[1]
|
|
50
|
+
commonHelpLinks()[1],
|
|
51
|
+
commonHelpLinks()[2]
|
|
48
52
|
])
|
|
49
53
|
|
|
50
54
|
module.exports = {
|
|
@@ -12,9 +12,9 @@ const getSettings = async config => {
|
|
|
12
12
|
const isSCAServicesAvailable = async config => {
|
|
13
13
|
const client = commonApi.getHttpClient(config)
|
|
14
14
|
return client
|
|
15
|
-
.
|
|
15
|
+
.scaServiceHealth(config)
|
|
16
16
|
.then(res => {
|
|
17
|
-
return res.
|
|
17
|
+
return res.body.status === 'UP'
|
|
18
18
|
})
|
|
19
19
|
.catch(err => {
|
|
20
20
|
console.log(err)
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
const { supportedLanguages: { JAVA, GO, PYTHON, RUBY, JAVASCRIPT, NODE, PHP, DOTNET } } = require('../../../constants/constants');
|
|
3
|
-
const { pollForSnapshotCompletion } = require('../../../audit/languageAnalysisEngine/sendSnapshot');
|
|
4
|
-
const { returnOra, startSpinner, succeedSpinner } = require('../../../utils/oraWrapper');
|
|
5
|
-
const { vulnerabilityReportV2 } = require('../../../audit/report/reportingFeature');
|
|
6
|
-
const autoDetection = require('../../../scan/autoDetection');
|
|
7
|
-
const treeUpload = require('../../../scaAnalysis/common/treeUpload');
|
|
8
|
-
const auditController = require('../../audit/auditController');
|
|
9
|
-
const rootFile = require('../../../audit/languageAnalysisEngine/getProjectRootFilenames');
|
|
10
|
-
const path = require('path');
|
|
11
|
-
const i18n = require('i18n');
|
|
12
|
-
const auditSave = require('../../../audit/save');
|
|
13
|
-
const { auditUsageGuide } = require('../../audit/help');
|
|
14
|
-
const repoMode = require('../../../scaAnalysis/repoMode/index');
|
|
15
|
-
const { dotNetAnalysis } = require('../../../scaAnalysis/dotnet');
|
|
16
|
-
const { goAnalysis } = require('../../../scaAnalysis/go/goAnalysis');
|
|
17
|
-
const { phpAnalysis } = require('../../../scaAnalysis/php/index');
|
|
18
|
-
const { rubyAnalysis } = require('../../../scaAnalysis/ruby');
|
|
19
|
-
const { pythonAnalysis } = require('../../../scaAnalysis/python');
|
|
20
|
-
const javaAnalysis = require('../../../scaAnalysis/java');
|
|
21
|
-
const jsAnalysis = require('../../../scaAnalysis/javascript');
|
|
22
|
-
const auditReport = require('../../../scaAnalysis/common/auditReport');
|
|
23
|
-
const scaUpload = require('../../../scaAnalysis/common/scaServicesUpload');
|
|
24
|
-
const settingsHelper = require('../../../utils/settingsHelper');
|
|
25
|
-
const chalk = require('chalk');
|
|
26
|
-
const saveResults = require('../../../scan/saveResults');
|
|
27
|
-
const { convertGenericToTypedReportModelSca } = require('../../../scaAnalysis/common/utils/reportUtilsSca');
|
|
28
|
-
const processSca = async (config) => {
|
|
29
|
-
config = await settingsHelper.getSettings(config);
|
|
30
|
-
const startTime = performance.now();
|
|
31
|
-
let filesFound;
|
|
32
|
-
if (config.help) {
|
|
33
|
-
console.log(auditUsageGuide);
|
|
34
|
-
process.exit(0);
|
|
35
|
-
}
|
|
36
|
-
const projectStats = await rootFile.getProjectStats(config.file);
|
|
37
|
-
let pathWithFile = projectStats.isFile();
|
|
38
|
-
config.fileName = config.file;
|
|
39
|
-
config.file = pathWithFile
|
|
40
|
-
? rootFile.getDirectoryFromPathGiven(config.file).concat('/')
|
|
41
|
-
: config.file;
|
|
42
|
-
if (config.fingerprint && config.experimental) {
|
|
43
|
-
let fingerprint = await autoDetection.autoDetectFingerprintInfo(config.file);
|
|
44
|
-
let idArray = fingerprint.map(x => x.id);
|
|
45
|
-
await saveResults.writeResultsToFile(fingerprint, 'fingerPrintInfo.json');
|
|
46
|
-
console.log(idArray);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config.file);
|
|
50
|
-
autoDetection.dealWithMultiJava(filesFound);
|
|
51
|
-
if (filesFound.length > 1 && pathWithFile) {
|
|
52
|
-
filesFound = filesFound.filter(i => Object.values(i)[0].includes(path.basename(config.fileName)));
|
|
53
|
-
}
|
|
54
|
-
let messageToSend = undefined;
|
|
55
|
-
if (filesFound.length === 1) {
|
|
56
|
-
switch (Object.keys(filesFound[0])[0]) {
|
|
57
|
-
case JAVA:
|
|
58
|
-
config.language = JAVA;
|
|
59
|
-
if (config.mode === 'repo') {
|
|
60
|
-
try {
|
|
61
|
-
return repoMode.buildRepo(config, filesFound[0]);
|
|
62
|
-
}
|
|
63
|
-
catch (e) {
|
|
64
|
-
throw new Error('Unable to build in repository mode. Check your project file');
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
messageToSend = await javaAnalysis.javaAnalysis(config, filesFound[0]);
|
|
69
|
-
}
|
|
70
|
-
break;
|
|
71
|
-
case JAVASCRIPT:
|
|
72
|
-
messageToSend = await jsAnalysis.jsAnalysis(config, filesFound[0]);
|
|
73
|
-
config.language = NODE;
|
|
74
|
-
break;
|
|
75
|
-
case PYTHON:
|
|
76
|
-
messageToSend = pythonAnalysis(config, filesFound[0]);
|
|
77
|
-
config.language = PYTHON;
|
|
78
|
-
break;
|
|
79
|
-
case RUBY:
|
|
80
|
-
messageToSend = rubyAnalysis(config, filesFound[0]);
|
|
81
|
-
config.language = RUBY;
|
|
82
|
-
break;
|
|
83
|
-
case PHP:
|
|
84
|
-
messageToSend = phpAnalysis(config, filesFound[0]);
|
|
85
|
-
config.language = PHP;
|
|
86
|
-
break;
|
|
87
|
-
case GO:
|
|
88
|
-
messageToSend = goAnalysis(config, filesFound[0]);
|
|
89
|
-
config.language = GO;
|
|
90
|
-
break;
|
|
91
|
-
case DOTNET:
|
|
92
|
-
messageToSend = dotNetAnalysis(config, filesFound[0]);
|
|
93
|
-
config.language = DOTNET;
|
|
94
|
-
break;
|
|
95
|
-
default:
|
|
96
|
-
console.log('No supported language detected in project path');
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
if (!config.applicationId) {
|
|
100
|
-
config.applicationId = await auditController.dealWithNoAppId(config);
|
|
101
|
-
}
|
|
102
|
-
if (config.experimental) {
|
|
103
|
-
console.log('');
|
|
104
|
-
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
|
|
105
|
-
startSpinner(reportSpinner);
|
|
106
|
-
const { reportArray, reportId } = await scaUpload.scaTreeUpload(messageToSend, config);
|
|
107
|
-
const reportModelLibraryList = convertGenericToTypedReportModelSca(reportArray);
|
|
108
|
-
auditReport.processAuditReport(config, reportModelLibraryList);
|
|
109
|
-
succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
|
|
110
|
-
if (config.save !== undefined) {
|
|
111
|
-
await auditSave.auditSave(config, reportId);
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
console.log('Use contrast audit --save to generate an SBOM');
|
|
115
|
-
}
|
|
116
|
-
const endTime = performance.now() - startTime;
|
|
117
|
-
const scanDurationMs = endTime - startTime;
|
|
118
|
-
console.log(`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
console.log('');
|
|
122
|
-
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
|
|
123
|
-
startSpinner(reportSpinner);
|
|
124
|
-
const snapshotResponse = await treeUpload.commonSendSnapShot(messageToSend, config);
|
|
125
|
-
await pollForSnapshotCompletion(config, snapshotResponse.id, reportSpinner);
|
|
126
|
-
succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
|
|
127
|
-
await vulnerabilityReportV2(config, snapshotResponse.id);
|
|
128
|
-
if (config.save !== undefined) {
|
|
129
|
-
await auditSave.auditSave(config);
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
console.log('\nUse contrast audit --save to generate an SBOM');
|
|
133
|
-
}
|
|
134
|
-
const endTime = performance.now() - startTime;
|
|
135
|
-
const scanDurationMs = endTime - startTime;
|
|
136
|
-
console.log(`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
if (filesFound.length === 0) {
|
|
141
|
-
console.log(i18n.__('languageAnalysisNoLanguage'));
|
|
142
|
-
console.log(i18n.__('languageAnalysisNoLanguageHelpLine'));
|
|
143
|
-
throw new Error();
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
console.log(chalk.bold(`\nMultiple language files detected \n`));
|
|
147
|
-
filesFound.forEach(file => {
|
|
148
|
-
console.log(`${Object.keys(file)[0]} : `, Object.values(file)[0]);
|
|
149
|
-
});
|
|
150
|
-
throw new Error(`Please use --file to audit one language only. \nExample: contrast audit --file package-lock.json`);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
module.exports = {
|
|
156
|
-
processSca
|
|
157
|
-
};
|