@contrast/contrast 1.0.0 → 1.0.3
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/.prettierignore +3 -0
- package/README.md +115 -78
- package/dist/audit/AnalysisEngine.js +37 -0
- package/dist/audit/catalogueApplication/catalogueApplication.js +36 -0
- package/dist/audit/dotnetAnalysisEngine/index.js +25 -0
- package/dist/audit/dotnetAnalysisEngine/parseLockFileContents.js +35 -0
- package/dist/audit/dotnetAnalysisEngine/parseProjectFileContents.js +15 -0
- package/dist/audit/dotnetAnalysisEngine/readLockFileContents.js +18 -0
- package/dist/audit/dotnetAnalysisEngine/readProjectFileContents.js +14 -0
- package/dist/audit/dotnetAnalysisEngine/sanitizer.js +9 -0
- package/dist/audit/goAnalysisEngine/index.js +17 -0
- package/dist/audit/goAnalysisEngine/parseProjectFileContents.js +164 -0
- package/dist/audit/goAnalysisEngine/readProjectFileContents.js +21 -0
- package/dist/audit/goAnalysisEngine/sanitizer.js +5 -0
- package/dist/audit/javaAnalysisEngine/index.js +34 -0
- package/dist/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +153 -0
- package/dist/audit/javaAnalysisEngine/parseProjectFileContents.js +353 -0
- package/dist/audit/javaAnalysisEngine/readProjectFileContents.js +98 -0
- package/dist/audit/javaAnalysisEngine/sanitizer.js +5 -0
- package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +24 -0
- package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +24 -0
- package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasLockFile.js +35 -0
- package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +23 -0
- package/dist/audit/languageAnalysisEngine/commonApi.js +18 -0
- package/dist/audit/languageAnalysisEngine/constants.js +20 -0
- package/dist/audit/languageAnalysisEngine/filterProjectPath.js +20 -0
- package/dist/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +25 -0
- package/dist/audit/languageAnalysisEngine/getProjectRootFilenames.js +39 -0
- package/dist/audit/languageAnalysisEngine/index.js +39 -0
- package/dist/audit/languageAnalysisEngine/langugageAnalysisFactory.js +95 -0
- package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +121 -0
- package/dist/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +17 -0
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +257 -0
- package/dist/audit/languageAnalysisEngine/report/newReportingFeature.js +81 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +133 -0
- package/dist/audit/languageAnalysisEngine/sendSnapshot.js +41 -0
- package/dist/audit/languageAnalysisEngine/util/capabilities.js +11 -0
- package/dist/audit/languageAnalysisEngine/util/generalAPI.js +39 -0
- package/dist/audit/languageAnalysisEngine/util/requestUtils.js +14 -0
- package/dist/audit/nodeAnalysisEngine/handleNPMLockFileV2.js +40 -0
- package/dist/audit/nodeAnalysisEngine/index.js +31 -0
- package/dist/audit/nodeAnalysisEngine/parseNPMLockFileContents.js +18 -0
- package/dist/audit/nodeAnalysisEngine/parseYarn2LockFileContents.js +51 -0
- package/dist/audit/nodeAnalysisEngine/parseYarnLockFileContents.js +18 -0
- package/dist/audit/nodeAnalysisEngine/readNPMLockFileContents.js +17 -0
- package/dist/audit/nodeAnalysisEngine/readProjectFileContents.js +14 -0
- package/dist/audit/nodeAnalysisEngine/readYarnLockFileContents.js +24 -0
- package/dist/audit/nodeAnalysisEngine/sanitizer.js +9 -0
- package/dist/audit/phpAnalysisEngine/index.js +23 -0
- package/dist/audit/phpAnalysisEngine/parseLockFileContents.js +52 -0
- package/dist/audit/phpAnalysisEngine/readLockFileContents.js +13 -0
- package/dist/audit/phpAnalysisEngine/readProjectFileContents.js +16 -0
- package/dist/audit/phpAnalysisEngine/sanitizer.js +5 -0
- package/dist/audit/pythonAnalysisEngine/index.js +25 -0
- package/dist/audit/pythonAnalysisEngine/parsePipfileLockContents.js +17 -0
- package/dist/audit/pythonAnalysisEngine/parseProjectFileContents.js +21 -0
- package/dist/audit/pythonAnalysisEngine/readPipfileLockFileContents.js +13 -0
- package/dist/audit/pythonAnalysisEngine/readPythonProjectFileContents.js +14 -0
- package/dist/audit/pythonAnalysisEngine/sanitizer.js +7 -0
- package/dist/audit/rubyAnalysisEngine/index.js +25 -0
- package/dist/audit/rubyAnalysisEngine/parseGemfileLockContents.js +176 -0
- package/dist/audit/rubyAnalysisEngine/parsedGemfile.js +22 -0
- package/dist/audit/rubyAnalysisEngine/readGemfileContents.js +14 -0
- package/dist/audit/rubyAnalysisEngine/readGemfileLockContents.js +14 -0
- package/dist/audit/rubyAnalysisEngine/sanitizer.js +6 -0
- package/dist/commands/audit/auditConfig.js +25 -0
- package/dist/commands/audit/auditController.js +31 -0
- package/dist/commands/audit/help.js +52 -0
- package/dist/commands/audit/processAudit.js +18 -0
- package/dist/commands/audit/saveFile.js +11 -0
- package/dist/commands/auth/auth.js +20 -2
- package/dist/commands/config/config.js +19 -8
- package/dist/commands/scan/processScan.js +9 -13
- package/dist/common/HTTPClient.js +112 -13
- package/dist/common/errorHandling.js +65 -1
- package/dist/common/versionChecker.js +30 -0
- package/dist/constants/constants.js +4 -2
- package/dist/constants/lambda.js +32 -4
- package/dist/constants/locales.js +60 -21
- package/dist/constants.js +181 -21
- package/dist/index.js +50 -23
- package/dist/lambda/aws.js +14 -11
- package/dist/lambda/help.js +4 -0
- package/dist/lambda/lambda.js +50 -27
- package/dist/lambda/lambdaUtils.js +72 -0
- package/dist/lambda/logUtils.js +11 -1
- package/dist/lambda/scanDetailCompletion.js +4 -4
- package/dist/lambda/scanRequest.js +11 -5
- package/dist/lambda/utils.js +110 -53
- package/dist/sbom/generateSbom.js +20 -0
- package/dist/scan/autoDetection.js +0 -32
- package/dist/scan/fileUtils.js +1 -1
- package/dist/scan/help.js +14 -40
- package/dist/scan/populateProjectIdAndProjectName.js +5 -0
- package/dist/scan/saveResults.js +14 -0
- package/dist/scan/scan.js +105 -40
- package/dist/scan/scanConfig.js +39 -0
- package/dist/scan/scanController.js +19 -16
- package/dist/scan/scanResults.js +24 -16
- package/dist/utils/commonApi.js +3 -3
- package/dist/utils/paramsUtil/commandlineParams.js +1 -20
- package/dist/utils/paramsUtil/paramHandler.js +3 -6
- package/dist/utils/parsedCLIOptions.js +14 -8
- package/dist/utils/requestUtils.js +1 -1
- package/dist/utils/saveFile.js +19 -0
- package/package.json +26 -21
- package/src/audit/AnalysisEngine.js +103 -0
- package/src/audit/catalogueApplication/catalogueApplication.js +42 -0
- package/src/audit/dotnetAnalysisEngine/index.js +26 -0
- package/src/audit/dotnetAnalysisEngine/parseLockFileContents.js +47 -0
- package/src/audit/dotnetAnalysisEngine/parseProjectFileContents.js +29 -0
- package/src/audit/dotnetAnalysisEngine/readLockFileContents.js +30 -0
- package/src/audit/dotnetAnalysisEngine/readProjectFileContents.js +26 -0
- package/src/audit/dotnetAnalysisEngine/sanitizer.js +11 -0
- package/src/audit/goAnalysisEngine/index.js +18 -0
- package/src/audit/goAnalysisEngine/parseProjectFileContents.js +209 -0
- package/src/audit/goAnalysisEngine/readProjectFileContents.js +31 -0
- package/src/audit/goAnalysisEngine/sanitizer.js +7 -0
- package/src/audit/javaAnalysisEngine/index.js +41 -0
- package/src/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +222 -0
- package/src/audit/javaAnalysisEngine/parseProjectFileContents.js +420 -0
- package/src/audit/javaAnalysisEngine/readProjectFileContents.js +141 -0
- package/src/audit/javaAnalysisEngine/sanitizer.js +6 -0
- package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +35 -0
- package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +41 -0
- package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasLockFile.js +54 -0
- package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +32 -0
- package/src/audit/languageAnalysisEngine/commonApi.js +20 -0
- package/src/audit/languageAnalysisEngine/constants.js +23 -0
- package/src/audit/languageAnalysisEngine/filterProjectPath.js +21 -0
- package/src/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +41 -0
- package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +72 -0
- package/src/audit/languageAnalysisEngine/index.js +45 -0
- package/src/audit/languageAnalysisEngine/langugageAnalysisFactory.js +126 -0
- package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +177 -0
- package/src/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +27 -0
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.js +303 -0
- package/src/audit/languageAnalysisEngine/report/newReportingFeature.js +124 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.js +190 -0
- package/src/audit/languageAnalysisEngine/sendSnapshot.js +51 -0
- package/src/audit/languageAnalysisEngine/util/capabilities.js +12 -0
- package/src/audit/languageAnalysisEngine/util/generalAPI.js +43 -0
- package/src/audit/languageAnalysisEngine/util/requestUtils.js +17 -0
- package/src/audit/nodeAnalysisEngine/handleNPMLockFileV2.js +49 -0
- package/src/audit/nodeAnalysisEngine/index.js +35 -0
- package/src/audit/nodeAnalysisEngine/parseNPMLockFileContents.js +20 -0
- package/src/audit/nodeAnalysisEngine/parseYarn2LockFileContents.js +63 -0
- package/src/audit/nodeAnalysisEngine/parseYarnLockFileContents.js +26 -0
- package/src/audit/nodeAnalysisEngine/readNPMLockFileContents.js +23 -0
- package/src/audit/nodeAnalysisEngine/readProjectFileContents.js +27 -0
- package/src/audit/nodeAnalysisEngine/readYarnLockFileContents.js +36 -0
- package/src/audit/nodeAnalysisEngine/sanitizer.js +11 -0
- package/src/audit/phpAnalysisEngine/index.js +27 -0
- package/src/audit/phpAnalysisEngine/parseLockFileContents.js +60 -0
- package/src/audit/phpAnalysisEngine/readLockFileContents.js +14 -0
- package/src/audit/phpAnalysisEngine/readProjectFileContents.js +25 -0
- package/src/audit/phpAnalysisEngine/sanitizer.js +4 -0
- package/src/audit/pythonAnalysisEngine/index.js +55 -0
- package/src/audit/pythonAnalysisEngine/parsePipfileLockContents.js +23 -0
- package/src/audit/pythonAnalysisEngine/parseProjectFileContents.js +33 -0
- package/src/audit/pythonAnalysisEngine/readPipfileLockFileContents.js +16 -0
- package/src/audit/pythonAnalysisEngine/readPythonProjectFileContents.js +22 -0
- package/src/audit/pythonAnalysisEngine/sanitizer.js +9 -0
- package/src/audit/rubyAnalysisEngine/index.js +30 -0
- package/src/audit/rubyAnalysisEngine/parseGemfileLockContents.js +215 -0
- package/src/audit/rubyAnalysisEngine/parsedGemfile.js +39 -0
- package/src/audit/rubyAnalysisEngine/readGemfileContents.js +18 -0
- package/src/audit/rubyAnalysisEngine/readGemfileLockContents.js +17 -0
- package/src/audit/rubyAnalysisEngine/sanitizer.js +8 -0
- package/src/commands/audit/auditConfig.ts +30 -0
- package/src/commands/audit/auditController.ts +31 -0
- package/src/commands/audit/help.ts +48 -0
- package/src/commands/audit/processAudit.ts +18 -0
- package/src/commands/audit/saveFile.ts +6 -0
- package/src/commands/auth/auth.js +26 -2
- package/src/commands/config/config.js +22 -8
- package/src/commands/scan/processScan.js +9 -13
- package/src/common/HTTPClient.js +149 -14
- package/src/common/errorHandling.ts +85 -2
- package/src/common/versionChecker.ts +39 -0
- package/src/constants/constants.js +5 -4
- package/src/constants/lambda.js +45 -4
- package/src/constants/locales.js +76 -26
- package/src/constants.js +204 -23
- package/src/index.ts +67 -27
- package/src/lambda/aws.ts +13 -12
- package/src/lambda/help.ts +4 -0
- package/src/lambda/lambda.ts +53 -34
- package/src/lambda/lambdaUtils.ts +111 -0
- package/src/lambda/logUtils.ts +19 -1
- package/src/lambda/scanDetailCompletion.ts +4 -4
- package/src/lambda/scanRequest.ts +13 -11
- package/src/lambda/utils.ts +149 -81
- package/src/sbom/generateSbom.ts +17 -0
- package/src/scan/autoDetection.js +0 -29
- package/src/scan/fileUtils.js +1 -1
- package/src/scan/help.js +14 -45
- package/src/scan/populateProjectIdAndProjectName.js +5 -0
- package/src/scan/saveResults.js +14 -0
- package/src/scan/scan.js +127 -58
- package/src/scan/scanConfig.js +54 -0
- package/src/scan/scanController.js +22 -15
- package/src/scan/scanResults.js +32 -19
- package/src/utils/commonApi.js +2 -3
- package/src/utils/getConfig.ts +2 -0
- package/src/utils/paramsUtil/commandlineParams.js +1 -26
- package/src/utils/paramsUtil/paramHandler.js +3 -7
- package/src/utils/parsedCLIOptions.js +11 -9
- package/src/utils/requestUtils.js +1 -1
- package/src/utils/saveFile.js +19 -0
- package/dist/lambda/scanDetail.js +0 -30
- package/dist/scan/fileFinder.js +0 -15
- package/dist/utils/paramsUtil/yamlParams.js +0 -6
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import commandLineUsage from 'command-line-usage'
|
|
2
|
+
import i18n from 'i18n'
|
|
3
|
+
import constants from '../../constants'
|
|
4
|
+
|
|
5
|
+
const auditUsageGuide = commandLineUsage([
|
|
6
|
+
{
|
|
7
|
+
header: i18n.__('auditHeader'),
|
|
8
|
+
content: [i18n.__('auditHeaderMessage')]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
header: i18n.__('constantsPrerequisitesHeader'),
|
|
12
|
+
content: [
|
|
13
|
+
'{bold ' +
|
|
14
|
+
i18n.__('constantsAuditPrerequisitesContentSupportedLanguages') +
|
|
15
|
+
'}',
|
|
16
|
+
'{bold ' +
|
|
17
|
+
i18n.__('constantsAuditPrerequisitesContentJava') +
|
|
18
|
+
'}' +
|
|
19
|
+
i18n.__('constantsAuditPrerequisitesContentMessage'),
|
|
20
|
+
'',
|
|
21
|
+
'{italic ' + i18n.__('constantsJavaNote') + '}',
|
|
22
|
+
'{italic ' + i18n.__('constantsJavaNoteGradle') + '}',
|
|
23
|
+
'',
|
|
24
|
+
'{bold ' +
|
|
25
|
+
i18n.__('constantsAuditPrerequisitesContentDotNet') +
|
|
26
|
+
'}' +
|
|
27
|
+
i18n.__('constantsAuditPrerequisitesContentDotNetMessage'),
|
|
28
|
+
'{bold ' +
|
|
29
|
+
i18n.__('constantsAuditPrerequisitesContentLanguageNode') +
|
|
30
|
+
'}' +
|
|
31
|
+
i18n.__('constantsAuditPrerequisitesContentLanguageNodeMessage'),
|
|
32
|
+
'{bold ' +
|
|
33
|
+
i18n.__('constantsAuditPrerequisitesContentLanguageRuby') +
|
|
34
|
+
'}' +
|
|
35
|
+
i18n.__('constantsAuditPrerequisitesContentLanguageRubyMessage'),
|
|
36
|
+
'{bold ' +
|
|
37
|
+
i18n.__('constantsAuditPrerequisitesContentLanguagePython') +
|
|
38
|
+
'}' +
|
|
39
|
+
i18n.__('constantsAuditPrerequisitesContentLanguagePythonMessage')
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
header: i18n.__('constantsAuditOptions'),
|
|
44
|
+
optionList: constants.commandLineDefinitions.auditOptionDefinitions
|
|
45
|
+
}
|
|
46
|
+
])
|
|
47
|
+
|
|
48
|
+
export { auditUsageGuide }
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { startAudit } from './auditController'
|
|
2
|
+
import { getAuditConfig } from './auditConfig'
|
|
3
|
+
import { auditUsageGuide } from './help'
|
|
4
|
+
|
|
5
|
+
export type parameterInput = string[]
|
|
6
|
+
|
|
7
|
+
export const processAudit = async (argv: parameterInput) => {
|
|
8
|
+
if (argv.indexOf('--help') != -1) {
|
|
9
|
+
printHelpMessage()
|
|
10
|
+
process.exit(1)
|
|
11
|
+
}
|
|
12
|
+
const config = getAuditConfig(argv)
|
|
13
|
+
const auditResults = await startAudit(config)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const printHelpMessage = () => {
|
|
17
|
+
console.log(auditUsageGuide)
|
|
18
|
+
}
|
|
@@ -11,8 +11,21 @@ const {
|
|
|
11
11
|
succeedSpinner
|
|
12
12
|
} = require('../../utils/oraWrapper')
|
|
13
13
|
const { TIMEOUT, AUTH_UI_URL } = require('../../constants/constants')
|
|
14
|
+
const parsedCLIOptions = require('../../utils/parsedCLIOptions')
|
|
15
|
+
const constants = require('../../constants')
|
|
16
|
+
const commandLineUsage = require('command-line-usage')
|
|
17
|
+
|
|
18
|
+
const processAuth = async (argv, config) => {
|
|
19
|
+
let authParams = parsedCLIOptions.getCommandLineArgsCustom(
|
|
20
|
+
argv,
|
|
21
|
+
constants.commandLineDefinitions.authOptionDefinitions
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
if (authParams.help) {
|
|
25
|
+
console.log(authUsageGuide)
|
|
26
|
+
process.exit(0)
|
|
27
|
+
}
|
|
14
28
|
|
|
15
|
-
const processAuth = async config => {
|
|
16
29
|
const token = uuidv4()
|
|
17
30
|
const url = `${AUTH_UI_URL}/?token=${token}`
|
|
18
31
|
|
|
@@ -44,7 +57,7 @@ const isAuthComplete = async (token, timeout, config) => {
|
|
|
44
57
|
let result = await pollAuthResult(token, client)
|
|
45
58
|
if (result.statusCode === 200) {
|
|
46
59
|
succeedSpinner(authSpinner, i18n.__('authSuccessMessage'))
|
|
47
|
-
console.log(i18n.__('
|
|
60
|
+
console.log(i18n.__('runAuthSuccessMessage'))
|
|
48
61
|
return result.body
|
|
49
62
|
}
|
|
50
63
|
let endTime = new Date() - startTime
|
|
@@ -68,6 +81,17 @@ const pollAuthResult = async (token, client) => {
|
|
|
68
81
|
})
|
|
69
82
|
}
|
|
70
83
|
|
|
84
|
+
const authUsageGuide = commandLineUsage([
|
|
85
|
+
{
|
|
86
|
+
header: i18n.__('authHeader'),
|
|
87
|
+
content: [i18n.__('constantsAuthHeaderContents')]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
header: i18n.__('constantsAuthUsageHeader'),
|
|
91
|
+
content: [i18n.__('constantsAuthUsageContents')]
|
|
92
|
+
}
|
|
93
|
+
])
|
|
94
|
+
|
|
71
95
|
module.exports = {
|
|
72
96
|
processAuth: processAuth
|
|
73
97
|
}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
const
|
|
1
|
+
const parsedCLIOptions = require('../../utils/parsedCLIOptions')
|
|
2
|
+
const constants = require('../../constants')
|
|
3
|
+
const commandLineUsage = require('command-line-usage')
|
|
4
|
+
const i18n = require('i18n')
|
|
2
5
|
|
|
3
6
|
const processConfig = (argv, config) => {
|
|
4
|
-
const options = [{ name: 'clear', alias: 'c', type: Boolean }]
|
|
5
|
-
|
|
6
7
|
try {
|
|
7
|
-
|
|
8
|
+
let configParams = parsedCLIOptions.getCommandLineArgsCustom(
|
|
8
9
|
argv,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
constants.commandLineDefinitions.configOptionDefinitions
|
|
11
|
+
)
|
|
12
|
+
if (configParams.help) {
|
|
13
|
+
console.log(configUsageGuide)
|
|
14
|
+
process.exit(0)
|
|
15
|
+
}
|
|
16
|
+
if (configParams.clear) {
|
|
13
17
|
config.clear()
|
|
14
18
|
} else {
|
|
15
19
|
console.log(JSON.parse(JSON.stringify(config.store)))
|
|
@@ -20,6 +24,16 @@ const processConfig = (argv, config) => {
|
|
|
20
24
|
}
|
|
21
25
|
}
|
|
22
26
|
|
|
27
|
+
const configUsageGuide = commandLineUsage([
|
|
28
|
+
{
|
|
29
|
+
header: i18n.__('configHeader')
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
content: [i18n.__('constantsConfigUsageContents')],
|
|
33
|
+
optionList: constants.commandLineDefinitions.configOptionDefinitions
|
|
34
|
+
}
|
|
35
|
+
])
|
|
36
|
+
|
|
23
37
|
module.exports = {
|
|
24
38
|
processConfig: processConfig
|
|
25
39
|
}
|
|
@@ -1,29 +1,25 @@
|
|
|
1
1
|
const { startScan } = require('../../scan/scanController')
|
|
2
|
-
const paramHandler = require('../../utils/paramsUtil/paramHandler')
|
|
3
2
|
const { formatScanOutput } = require('../../scan/scan')
|
|
4
3
|
const { scanUsageGuide } = require('../../scan/help')
|
|
4
|
+
const scanConfig = require('../../scan/scanConfig')
|
|
5
|
+
const { saveScanFile } = require('../../utils/saveFile')
|
|
5
6
|
|
|
6
|
-
const processScan = async
|
|
7
|
-
let
|
|
8
|
-
if (getScanSubCommands.help) {
|
|
9
|
-
printHelpMessage()
|
|
10
|
-
process.exit(1)
|
|
11
|
-
}
|
|
7
|
+
const processScan = async argvMain => {
|
|
8
|
+
let config = scanConfig.getScanConfig(argvMain)
|
|
12
9
|
|
|
13
|
-
let scanResults = await startScan()
|
|
10
|
+
let scanResults = await startScan(config)
|
|
14
11
|
if (scanResults) {
|
|
15
12
|
formatScanOutput(
|
|
16
13
|
scanResults?.projectOverview,
|
|
17
14
|
scanResults?.scanResultsInstances
|
|
18
15
|
)
|
|
19
16
|
}
|
|
20
|
-
}
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
if (config.save !== undefined) {
|
|
19
|
+
await saveScanFile(config, scanResults)
|
|
20
|
+
}
|
|
24
21
|
}
|
|
25
22
|
|
|
26
23
|
module.exports = {
|
|
27
|
-
processScan
|
|
28
|
-
printHelpMessage
|
|
24
|
+
processScan
|
|
29
25
|
}
|
package/src/common/HTTPClient.js
CHANGED
|
@@ -6,10 +6,10 @@ const { AUTH_CALLBACK_URL } = require('../constants/constants')
|
|
|
6
6
|
function HTTPClient(config) {
|
|
7
7
|
const apiKey = config.apiKey
|
|
8
8
|
const authToken = config.authorization
|
|
9
|
-
|
|
9
|
+
this.rejectUnauthorized = !config.ignoreCertErrors
|
|
10
10
|
|
|
11
|
-
const superApiKey = config.
|
|
12
|
-
const superAuthToken = config.
|
|
11
|
+
const superApiKey = config.superApiKey
|
|
12
|
+
const superAuthToken = config.superAuthorization
|
|
13
13
|
|
|
14
14
|
this.requestOptions = {
|
|
15
15
|
forever: true,
|
|
@@ -91,6 +91,15 @@ HTTPClient.prototype.getSpecificScanResult = function getSpecificScanResult(
|
|
|
91
91
|
return requestUtils.sendRequest({ method: 'get', options })
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
HTTPClient.prototype.getSpecificScanResultSarif = function getSpecificScanResultSarif(
|
|
95
|
+
config,
|
|
96
|
+
scanId
|
|
97
|
+
) {
|
|
98
|
+
const options = _.cloneDeep(this.requestOptions)
|
|
99
|
+
options.url = createRawOutputURL(config, scanId)
|
|
100
|
+
return requestUtils.sendRequest({ method: 'get', options })
|
|
101
|
+
}
|
|
102
|
+
|
|
94
103
|
HTTPClient.prototype.getScanId = function getScanId(config, codeArtifactId) {
|
|
95
104
|
const options = _.cloneDeep(this.requestOptions)
|
|
96
105
|
let url = createGetScanIdURL(config)
|
|
@@ -119,8 +128,10 @@ HTTPClient.prototype.createProjectId = function createProjectId(config) {
|
|
|
119
128
|
|
|
120
129
|
options.body = {
|
|
121
130
|
name: config.name,
|
|
122
|
-
archived: 'false'
|
|
123
|
-
|
|
131
|
+
archived: 'false'
|
|
132
|
+
}
|
|
133
|
+
if (config.language) {
|
|
134
|
+
options.body.language = config.language
|
|
124
135
|
}
|
|
125
136
|
options.url = createHarmonyProjectsUrl(config)
|
|
126
137
|
return requestUtils.sendRequest({ method: 'post', options })
|
|
@@ -159,6 +170,80 @@ HTTPClient.prototype.pollForAuth = function pollForAuth(token) {
|
|
|
159
170
|
return requestUtils.sendRequest({ method: 'post', options })
|
|
160
171
|
}
|
|
161
172
|
|
|
173
|
+
HTTPClient.prototype.catalogueCommand = function catalogueCommand(config) {
|
|
174
|
+
const options = _.cloneDeep(this.requestOptions)
|
|
175
|
+
let url = createAppCreateURL(config)
|
|
176
|
+
options.url = url
|
|
177
|
+
|
|
178
|
+
let requestBody = {}
|
|
179
|
+
requestBody.name = config.applicationName
|
|
180
|
+
requestBody.language = config.language.toUpperCase()
|
|
181
|
+
requestBody.appGroups = config.appGroups
|
|
182
|
+
requestBody.metadata = config.metadata
|
|
183
|
+
requestBody.tags = config.tags
|
|
184
|
+
requestBody.code = config.code
|
|
185
|
+
options.body = requestBody
|
|
186
|
+
|
|
187
|
+
return requestUtils.sendRequest({ method: 'post', options })
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
HTTPClient.prototype.sendSnapshot = function sendSnapshot(requestBody, config) {
|
|
191
|
+
const options = _.cloneDeep(this.requestOptions)
|
|
192
|
+
let url = createSnapshotURL(config)
|
|
193
|
+
options.url = url
|
|
194
|
+
options.body = requestBody
|
|
195
|
+
return requestUtils.sendRequest({ method: 'post', options })
|
|
196
|
+
}
|
|
197
|
+
|
|
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
|
+
) {
|
|
210
|
+
const options = _.cloneDeep(this.requestOptions)
|
|
211
|
+
let url = createSpecificReportUrl(config, reportId)
|
|
212
|
+
options.url = url
|
|
213
|
+
|
|
214
|
+
return requestUtils.sendRequest({ method: 'get', options })
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
HTTPClient.prototype.getLibraryVulnerabilities = function getLibraryVulnerabilities(
|
|
218
|
+
requestBody,
|
|
219
|
+
config
|
|
220
|
+
) {
|
|
221
|
+
const options = _.cloneDeep(this.requestOptions)
|
|
222
|
+
let url = createLibraryVulnerabilitiesUrl(config)
|
|
223
|
+
options.url = url
|
|
224
|
+
options.body = requestBody
|
|
225
|
+
|
|
226
|
+
return requestUtils.sendRequest({ method: 'put', options })
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
HTTPClient.prototype.getAppId = function getAppId(config) {
|
|
230
|
+
const options = _.cloneDeep(this.requestOptions)
|
|
231
|
+
let url = createAppNameUrl(config)
|
|
232
|
+
options.url = url
|
|
233
|
+
return requestUtils.sendRequest({ method: 'get', options })
|
|
234
|
+
}
|
|
235
|
+
|
|
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
|
+
}
|
|
246
|
+
|
|
162
247
|
// serverless - lambda
|
|
163
248
|
function getServerlessHost(config = {}) {
|
|
164
249
|
const originalHost = config?.host || config?.get('host')
|
|
@@ -195,10 +280,10 @@ function createScanResultsGetUrl(config, params, scanId, functionArn) {
|
|
|
195
280
|
|
|
196
281
|
HTTPClient.prototype.postFunctionScan = async function postFunctionScan(
|
|
197
282
|
config,
|
|
198
|
-
|
|
283
|
+
params,
|
|
199
284
|
body
|
|
200
285
|
) {
|
|
201
|
-
const url = createScanFunctionPostUrl(config,
|
|
286
|
+
const url = createScanFunctionPostUrl(config, params)
|
|
202
287
|
const options = { ...this.requestOptions, body, url }
|
|
203
288
|
|
|
204
289
|
return requestUtils.sendRequest({ method: 'post', options })
|
|
@@ -206,10 +291,10 @@ HTTPClient.prototype.postFunctionScan = async function postFunctionScan(
|
|
|
206
291
|
|
|
207
292
|
HTTPClient.prototype.getScanResources = async function getScanResources(
|
|
208
293
|
config,
|
|
209
|
-
|
|
294
|
+
params,
|
|
210
295
|
scanId
|
|
211
296
|
) {
|
|
212
|
-
const url = createScanResourcesGetUrl(config,
|
|
297
|
+
const url = createScanResourcesGetUrl(config, params, scanId)
|
|
213
298
|
const options = { ...this.requestOptions, url }
|
|
214
299
|
|
|
215
300
|
return requestUtils.sendRequest({ method: 'get', options })
|
|
@@ -217,27 +302,41 @@ HTTPClient.prototype.getScanResources = async function getScanResources(
|
|
|
217
302
|
|
|
218
303
|
HTTPClient.prototype.getFunctionScanResults = async function getFunctionScanResults(
|
|
219
304
|
config,
|
|
220
|
-
|
|
305
|
+
params,
|
|
221
306
|
scanId,
|
|
222
307
|
functionArn
|
|
223
308
|
) {
|
|
224
|
-
const url = createScanResultsGetUrl(config,
|
|
309
|
+
const url = createScanResultsGetUrl(config, params, scanId, functionArn)
|
|
225
310
|
const options = { ...this.requestOptions, url }
|
|
226
311
|
|
|
227
312
|
return requestUtils.sendRequest({ method: 'get', options })
|
|
228
313
|
}
|
|
229
314
|
|
|
315
|
+
HTTPClient.prototype.checkLibrary = function checkLibrary(data) {
|
|
316
|
+
const options = _.cloneDeep(this.requestOptions)
|
|
317
|
+
let url = createDataUrl()
|
|
318
|
+
options.url = url
|
|
319
|
+
options.body = data
|
|
320
|
+
return requestUtils.sendRequest({ method: 'post', options })
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
HTTPClient.prototype.getSbom = function getSbom(config) {
|
|
324
|
+
const options = _.cloneDeep(this.requestOptions)
|
|
325
|
+
options.url = createSbomCycloneDXUrl(config)
|
|
326
|
+
return requestUtils.sendRequest({ method: 'get', options })
|
|
327
|
+
}
|
|
328
|
+
|
|
230
329
|
// scan
|
|
231
330
|
const createGetScanIdURL = config => {
|
|
232
331
|
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/scans/`
|
|
233
332
|
}
|
|
234
333
|
|
|
235
334
|
const createScanResultsInstancesURL = (config, scanId) => {
|
|
236
|
-
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/scans/${scanId}/result-instances?sort=severity,asc`
|
|
335
|
+
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/scans/${scanId}/result-instances/info?size=50&page=0&last=false&sort=severity,asc`
|
|
237
336
|
}
|
|
238
337
|
|
|
239
|
-
const createRawOutputURL = (config,
|
|
240
|
-
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/scans/${
|
|
338
|
+
const createRawOutputURL = (config, scanId) => {
|
|
339
|
+
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/scans/${scanId}/raw-output`
|
|
241
340
|
}
|
|
242
341
|
|
|
243
342
|
const createSpecificScanResultURL = (config, scanId) => {
|
|
@@ -264,6 +363,42 @@ const pollForAuthUrl = () => {
|
|
|
264
363
|
return `${AUTH_CALLBACK_URL}/auth/credentials`
|
|
265
364
|
}
|
|
266
365
|
|
|
366
|
+
function createSnapshotURL(config) {
|
|
367
|
+
return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/${config.applicationId}/snapshots`
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const createAppCreateURL = config => {
|
|
371
|
+
return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/create`
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const createAppNameUrl = config => {
|
|
375
|
+
return `${config.host}/Contrast/api/ng/${config.organizationId}/applications/name?filterText=${config.applicationName}`
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function createLibraryVulnerabilitiesUrl(config) {
|
|
379
|
+
return `${config.host}/Contrast/api/ng/${config.organizationId}/libraries/artifactsByGroupNameVersion`
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function createReportUrl(config) {
|
|
383
|
+
return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/${config.applicationId}/reports`
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function createSpecificReportUrl(config, reportId) {
|
|
387
|
+
return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/${config.applicationId}/reports/${reportId}?nodesToInclude=PROD`
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function createDataUrl() {
|
|
391
|
+
return `https://ardy.contrastsecurity.com/production`
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const createGetDependencyTree = (protocol, orgUuid, appId, reportId) => {
|
|
395
|
+
return `${protocol}/Contrast/api/ng/sca/organizations/${orgUuid}/applications/${appId}/reports/${reportId}`
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function createSbomCycloneDXUrl(config) {
|
|
399
|
+
return `${config.host}/Contrast/api/ng/${config.organizationId}/applications/${config.applicationId}/libraries/sbom/cyclonedx`
|
|
400
|
+
}
|
|
401
|
+
|
|
267
402
|
module.exports = HTTPClient
|
|
268
403
|
module.exports.pollForAuthUrl = pollForAuthUrl
|
|
269
404
|
module.exports.getServerlessHost = getServerlessHost
|
|
@@ -1,4 +1,58 @@
|
|
|
1
1
|
import i18n from 'i18n'
|
|
2
|
+
import { sortBy } from 'lodash'
|
|
3
|
+
|
|
4
|
+
const handleResponseErrors = (res: any, api: string) => {
|
|
5
|
+
if (res.statusCode === 400) {
|
|
6
|
+
api === 'catalogue' ? badRequestError(true) : badRequestError(false)
|
|
7
|
+
} else if (res.statusCode === 401) {
|
|
8
|
+
unauthenticatedError()
|
|
9
|
+
} else if (res.statusCode === 403) {
|
|
10
|
+
forbiddenError()
|
|
11
|
+
} else if (res.statusCode === 407) {
|
|
12
|
+
proxyError()
|
|
13
|
+
} else {
|
|
14
|
+
if (api === 'snapshot' || api === 'catalogue') {
|
|
15
|
+
snapshotFailureError()
|
|
16
|
+
}
|
|
17
|
+
if (api === 'vulnerabilities') {
|
|
18
|
+
vulnerabilitiesFailureError()
|
|
19
|
+
}
|
|
20
|
+
if (api === 'report') {
|
|
21
|
+
reportFailureError()
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const libraryAnalysisError = () => {
|
|
27
|
+
console.log(i18n.__('libraryAnalysisError'))
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const snapshotFailureError = () => {
|
|
31
|
+
console.log(
|
|
32
|
+
'\n ******************************** ' +
|
|
33
|
+
i18n.__('snapshotFailureHeader') +
|
|
34
|
+
' *********************************\n' +
|
|
35
|
+
i18n.__('snapshotFailureMessage')
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const vulnerabilitiesFailureError = () => {
|
|
40
|
+
console.log(
|
|
41
|
+
'\n ******************************** ' +
|
|
42
|
+
i18n.__('snapshotFailureHeader') +
|
|
43
|
+
' *********************************\n' +
|
|
44
|
+
i18n.__('vulnerabilitiesFailureMessage')
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const reportFailureError = () => {
|
|
49
|
+
console.log(
|
|
50
|
+
'\n ******************************** ' +
|
|
51
|
+
i18n.__('snapshotFailureHeader') +
|
|
52
|
+
' *********************************\n' +
|
|
53
|
+
i18n.__('reportFailureMessage')
|
|
54
|
+
)
|
|
55
|
+
}
|
|
2
56
|
|
|
3
57
|
const genericError = (missingCliOption: string) => {
|
|
4
58
|
// prettier-ignore
|
|
@@ -19,6 +73,7 @@ const badRequestError = (catalogue: boolean) => {
|
|
|
19
73
|
|
|
20
74
|
const forbiddenError = () => {
|
|
21
75
|
generalError('forbiddenRequestErrorHeader', 'forbiddenRequestErrorMessage')
|
|
76
|
+
process.exit(1)
|
|
22
77
|
}
|
|
23
78
|
|
|
24
79
|
const proxyError = () => {
|
|
@@ -51,7 +106,7 @@ const getErrorMessage = (header: string, message?: string) => {
|
|
|
51
106
|
const multiLine = message?.includes('\n')
|
|
52
107
|
let finalMessage = ''
|
|
53
108
|
|
|
54
|
-
// i18n split the line if it includes
|
|
109
|
+
// i18n split the line if it includes '\n'
|
|
55
110
|
if (multiLine) {
|
|
56
111
|
finalMessage = `\n${message}`
|
|
57
112
|
} else if (message) {
|
|
@@ -66,6 +121,31 @@ const generalError = (header: string, message?: string) => {
|
|
|
66
121
|
console.log(finalMessage)
|
|
67
122
|
}
|
|
68
123
|
|
|
124
|
+
const findCommandOnError = (unknownOptions: string[]) => {
|
|
125
|
+
const commandKeywords = {
|
|
126
|
+
auth: 'auth',
|
|
127
|
+
audit: 'audit',
|
|
128
|
+
scan: 'scan',
|
|
129
|
+
lambda: 'lambda',
|
|
130
|
+
config: 'config'
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const containsCommandKeyword = unknownOptions.some(
|
|
134
|
+
// @ts-ignore
|
|
135
|
+
command => commandKeywords[command]
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
if (containsCommandKeyword) {
|
|
139
|
+
const foundCommands = unknownOptions.filter(
|
|
140
|
+
// @ts-ignore
|
|
141
|
+
command => commandKeywords[command]
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
//return the first command found
|
|
145
|
+
return foundCommands[0]
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
69
149
|
export {
|
|
70
150
|
genericError,
|
|
71
151
|
unauthenticatedError,
|
|
@@ -75,5 +155,8 @@ export {
|
|
|
75
155
|
failOptionError,
|
|
76
156
|
hostWarningError,
|
|
77
157
|
generalError,
|
|
78
|
-
getErrorMessage
|
|
158
|
+
getErrorMessage,
|
|
159
|
+
handleResponseErrors,
|
|
160
|
+
libraryAnalysisError,
|
|
161
|
+
findCommandOnError
|
|
79
162
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import latestVersion from 'latest-version'
|
|
2
|
+
import { APP_VERSION } from '../constants/constants'
|
|
3
|
+
import boxen from 'boxen'
|
|
4
|
+
import chalk from 'chalk'
|
|
5
|
+
import semver from 'semver'
|
|
6
|
+
|
|
7
|
+
export async function findLatestCLIVersion() {
|
|
8
|
+
const latestCLIVersion = await latestVersion('@contrast/contrast')
|
|
9
|
+
|
|
10
|
+
if (semver.lt(APP_VERSION, latestCLIVersion)) {
|
|
11
|
+
const updateAvailableMessage = `Update available ${chalk.yellow(
|
|
12
|
+
APP_VERSION
|
|
13
|
+
)} → ${chalk.green(latestCLIVersion)}`
|
|
14
|
+
|
|
15
|
+
const npmUpdateAvailableCommand = `Run ${chalk.cyan(
|
|
16
|
+
'npm i @contrast/contrast -g'
|
|
17
|
+
)} to update via npm`
|
|
18
|
+
|
|
19
|
+
const homebrewUpdateAvailableCommand = `Run ${chalk.cyan(
|
|
20
|
+
'brew install contrastsecurity/tap/contrast'
|
|
21
|
+
)} to update via brew`
|
|
22
|
+
|
|
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
|
+
}
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function isCorrectNodeVersion(currentVersion: string) {
|
|
38
|
+
return semver.satisfies(currentVersion, '>=16.13.2 <17')
|
|
39
|
+
}
|
|
@@ -8,17 +8,17 @@ const GO = 'GO'
|
|
|
8
8
|
// we set the langauge as Node instead of PHP since we're using the Node engine in TS
|
|
9
9
|
const PHP = 'PHP'
|
|
10
10
|
const JAVASCRIPT = 'JAVASCRIPT'
|
|
11
|
-
|
|
12
11
|
const LOW = 'LOW'
|
|
13
12
|
const MEDIUM = 'MEDIUM'
|
|
14
13
|
const HIGH = 'HIGH'
|
|
15
14
|
const CRITICAL = 'CRITICAL'
|
|
16
|
-
|
|
17
15
|
const APP_NAME = 'contrast'
|
|
18
|
-
const APP_VERSION = '1.0.
|
|
16
|
+
const APP_VERSION = '1.0.3'
|
|
19
17
|
const TIMEOUT = 120000
|
|
18
|
+
|
|
20
19
|
const AUTH_UI_URL = 'https://cli-auth.contrastsecurity.com'
|
|
21
20
|
const AUTH_CALLBACK_URL = 'https://cli-auth-api.contrastsecurity.com'
|
|
21
|
+
const SARIF_FILE = 'SARIF'
|
|
22
22
|
|
|
23
23
|
module.exports = {
|
|
24
24
|
supportedLanguages: { NODE, DOTNET, JAVA, RUBY, PYTHON, GO, PHP, JAVASCRIPT },
|
|
@@ -30,5 +30,6 @@ module.exports = {
|
|
|
30
30
|
APP_NAME,
|
|
31
31
|
TIMEOUT,
|
|
32
32
|
AUTH_UI_URL,
|
|
33
|
-
AUTH_CALLBACK_URL
|
|
33
|
+
AUTH_CALLBACK_URL,
|
|
34
|
+
SARIF_FILE
|
|
34
35
|
}
|