@contrast/contrast 1.0.1 → 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.
- package/.prettierignore +2 -0
- package/README.md +103 -133
- package/dist/audit/languageAnalysisEngine/{langugageAnalysisFactory.js → languageAnalysisFactory.js} +26 -11
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +62 -234
- package/dist/audit/languageAnalysisEngine/report/models/reportLibraryModel.js +19 -0
- package/dist/audit/languageAnalysisEngine/report/models/reportListModel.js +24 -0
- package/dist/audit/languageAnalysisEngine/report/models/reportSeverityModel.js +10 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +24 -129
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +85 -0
- package/dist/audit/languageAnalysisEngine/sendSnapshot.js +3 -1
- package/dist/commands/audit/auditController.js +6 -3
- package/dist/commands/audit/saveFile.js +11 -0
- package/dist/commands/auth/auth.js +19 -1
- package/dist/commands/config/config.js +19 -8
- package/dist/commands/scan/processScan.js +8 -25
- package/dist/common/HTTPClient.js +30 -26
- package/dist/common/errorHandling.js +17 -1
- package/dist/common/versionChecker.js +32 -0
- package/dist/constants/constants.js +4 -2
- package/dist/constants/lambda.js +3 -1
- package/dist/constants/locales.js +41 -18
- package/dist/constants.js +39 -3
- package/dist/index.js +49 -28
- package/dist/lambda/help.js +22 -14
- package/dist/lambda/lambda.js +6 -0
- package/dist/sbom/generateSbom.js +20 -0
- package/dist/scan/help.js +4 -2
- package/dist/scan/models/groupedResultsModel.js +10 -0
- package/dist/scan/models/resultContentModel.js +2 -0
- package/dist/scan/models/scanResultsModel.js +11 -0
- package/dist/scan/populateProjectIdAndProjectName.js +1 -0
- package/dist/scan/saveResults.js +9 -10
- package/dist/scan/scan.js +99 -74
- package/dist/scan/scanConfig.js +20 -1
- package/dist/scan/scanController.js +7 -2
- package/dist/scan/scanResults.js +6 -0
- package/dist/utils/getConfig.js +3 -0
- package/dist/utils/paramsUtil/commandlineParams.js +1 -1
- package/dist/utils/requestUtils.js +1 -1
- package/dist/utils/saveFile.js +19 -0
- package/package.json +2 -2
- package/src/audit/languageAnalysisEngine/{langugageAnalysisFactory.js → languageAnalysisFactory.js} +33 -15
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +127 -0
- package/src/audit/languageAnalysisEngine/report/models/reportLibraryModel.ts +30 -0
- package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +32 -0
- package/src/audit/languageAnalysisEngine/report/models/reportSeverityModel.ts +9 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +56 -0
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +110 -0
- package/src/audit/languageAnalysisEngine/sendSnapshot.js +3 -1
- package/src/commands/audit/auditController.ts +12 -3
- package/src/commands/audit/processAudit.ts +0 -1
- package/src/commands/audit/saveFile.ts +6 -0
- package/src/commands/auth/auth.js +25 -1
- package/src/commands/config/config.js +22 -8
- package/src/commands/scan/processScan.js +8 -29
- package/src/common/HTTPClient.js +42 -36
- package/src/common/errorHandling.ts +29 -2
- package/src/common/versionChecker.ts +41 -0
- package/src/constants/constants.js +5 -4
- package/src/constants/lambda.js +3 -1
- package/src/constants/locales.js +51 -19
- package/src/constants.js +44 -3
- package/src/index.ts +63 -31
- package/src/lambda/help.ts +22 -14
- package/src/lambda/lambda.ts +8 -0
- package/src/sbom/generateSbom.ts +17 -0
- package/src/scan/help.js +4 -2
- package/src/scan/models/groupedResultsModel.ts +18 -0
- package/src/scan/models/resultContentModel.ts +86 -0
- package/src/scan/models/scanResultsModel.ts +52 -0
- package/src/scan/populateProjectIdAndProjectName.js +1 -0
- package/src/scan/saveResults.js +8 -9
- package/src/scan/scan.ts +192 -0
- package/src/scan/scanConfig.js +26 -1
- package/src/scan/scanController.js +11 -2
- package/src/scan/scanResults.js +11 -0
- package/src/utils/getConfig.ts +12 -0
- package/src/utils/paramsUtil/commandlineParams.js +1 -1
- package/src/utils/requestUtils.js +1 -1
- package/src/utils/saveFile.js +19 -0
- package/dist/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +0 -17
- package/dist/audit/languageAnalysisEngine/report/newReportingFeature.js +0 -81
- package/dist/common/findLatestCLIVersion.js +0 -23
- package/dist/lambda/scanDetail.js +0 -30
- package/dist/scan/fileFinder.js +0 -15
- package/dist/utils/fileUtils.js +0 -31
- package/dist/utils/paramsUtil/genericCommandLineParams.js +0 -12
- package/dist/utils/paramsUtil/yamlParams.js +0 -6
- package/src/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +0 -27
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.js +0 -303
- package/src/audit/languageAnalysisEngine/report/newReportingFeature.js +0 -124
- package/src/audit/languageAnalysisEngine/report/reportingFeature.js +0 -190
- package/src/common/findLatestCLIVersion.ts +0 -27
- package/src/scan/scan.js +0 -162
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createLibraryHeader,
|
|
3
|
+
getReport,
|
|
4
|
+
printVulnerabilityResponse
|
|
5
|
+
} from './commonReportingFunctions'
|
|
6
|
+
import {
|
|
7
|
+
convertGenericToTypedLibraries,
|
|
8
|
+
severityCount
|
|
9
|
+
} from './utils/reportUtils'
|
|
10
|
+
|
|
11
|
+
export async function vulnerabilityReport(
|
|
12
|
+
analysis: any,
|
|
13
|
+
applicationId: string,
|
|
14
|
+
reportId: string
|
|
15
|
+
) {
|
|
16
|
+
const reportResponse = await getReport(analysis.config, reportId)
|
|
17
|
+
|
|
18
|
+
if (reportResponse !== undefined) {
|
|
19
|
+
const id = applicationId
|
|
20
|
+
const name = analysis.config.applicationName
|
|
21
|
+
formatVulnerabilityOutput(
|
|
22
|
+
reportResponse.vulnerabilities,
|
|
23
|
+
id,
|
|
24
|
+
name,
|
|
25
|
+
analysis.config
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function formatVulnerabilityOutput(
|
|
31
|
+
libraryVulnerabilityResponse: any,
|
|
32
|
+
id: string,
|
|
33
|
+
name: string,
|
|
34
|
+
config: any
|
|
35
|
+
) {
|
|
36
|
+
const vulnerableLibraries = convertGenericToTypedLibraries(
|
|
37
|
+
libraryVulnerabilityResponse
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
const numberOfVulnerableLibraries = vulnerableLibraries.length
|
|
41
|
+
let numberOfCves = 0
|
|
42
|
+
vulnerableLibraries.forEach(lib => (numberOfCves += lib.cveArray.length))
|
|
43
|
+
|
|
44
|
+
createLibraryHeader(id, numberOfVulnerableLibraries, numberOfCves, name)
|
|
45
|
+
|
|
46
|
+
const hasSomeVulnerabilitiesReported = printVulnerabilityResponse(
|
|
47
|
+
vulnerableLibraries,
|
|
48
|
+
config
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
return [
|
|
52
|
+
hasSomeVulnerabilitiesReported,
|
|
53
|
+
numberOfCves,
|
|
54
|
+
severityCount(vulnerableLibraries)
|
|
55
|
+
]
|
|
56
|
+
}
|
|
@@ -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
|
-
|
|
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('
|
|
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
|
-
|
|
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
|
|
|
@@ -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
|
|
|
@@ -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,44 +1,23 @@
|
|
|
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
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
4
|
+
const { saveScanFile } = require('../../utils/saveFile')
|
|
5
|
+
const { ScanResultsModel } = require('../../scan/models/scanResultsModel')
|
|
6
|
+
const { formatScanOutput } = require('../../scan/scan')
|
|
8
7
|
|
|
9
8
|
const processScan = async argvMain => {
|
|
10
|
-
if (argvMain.indexOf('--help') !== -1) {
|
|
11
|
-
printHelpMessage()
|
|
12
|
-
process.exit(1)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
9
|
let config = scanConfig.getScanConfig(argvMain)
|
|
16
10
|
|
|
17
|
-
let scanResults = await startScan(config)
|
|
11
|
+
let scanResults = new ScanResultsModel(await startScan(config))
|
|
18
12
|
if (scanResults) {
|
|
19
|
-
formatScanOutput(
|
|
20
|
-
scanResults?.projectOverview,
|
|
21
|
-
scanResults?.scanResultsInstances
|
|
22
|
-
)
|
|
13
|
+
formatScanOutput(scanResults)
|
|
23
14
|
}
|
|
24
15
|
|
|
25
|
-
if (config.save) {
|
|
26
|
-
|
|
27
|
-
const scanId = scanResults.scanDetail.id
|
|
28
|
-
const client = commonApi.getHttpClient(config)
|
|
29
|
-
const rawResults = await client.getSpecificScanResultSarif(config, scanId)
|
|
30
|
-
saveResults.writeResultsToFile(rawResults?.body)
|
|
31
|
-
} else {
|
|
32
|
-
console.log(i18n.__('scanNoFiletypeSpecifiedForSave'))
|
|
33
|
-
}
|
|
16
|
+
if (config.save !== undefined) {
|
|
17
|
+
await saveScanFile(config, scanResults)
|
|
34
18
|
}
|
|
35
19
|
}
|
|
36
20
|
|
|
37
|
-
const printHelpMessage = () => {
|
|
38
|
-
console.log(scanUsageGuide)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
21
|
module.exports = {
|
|
42
|
-
processScan
|
|
43
|
-
printHelpMessage
|
|
22
|
+
processScan
|
|
44
23
|
}
|
package/src/common/HTTPClient.js
CHANGED
|
@@ -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:
|
|
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
|
}
|
|
@@ -130,6 +132,9 @@ HTTPClient.prototype.createProjectId = function createProjectId(config) {
|
|
|
130
132
|
name: config.name,
|
|
131
133
|
archived: 'false'
|
|
132
134
|
}
|
|
135
|
+
if (config.language) {
|
|
136
|
+
options.body.language = config.language
|
|
137
|
+
}
|
|
133
138
|
options.url = createHarmonyProjectsUrl(config)
|
|
134
139
|
return requestUtils.sendRequest({ method: 'post', options })
|
|
135
140
|
}
|
|
@@ -185,6 +190,9 @@ HTTPClient.prototype.catalogueCommand = function catalogueCommand(config) {
|
|
|
185
190
|
}
|
|
186
191
|
|
|
187
192
|
HTTPClient.prototype.sendSnapshot = function sendSnapshot(requestBody, config) {
|
|
193
|
+
if (config.language.toUpperCase() === 'RUBY') {
|
|
194
|
+
console.log('sendSnapshot requestBody', requestBody.snapshot.ruby)
|
|
195
|
+
}
|
|
188
196
|
const options = _.cloneDeep(this.requestOptions)
|
|
189
197
|
let url = createSnapshotURL(config)
|
|
190
198
|
options.url = url
|
|
@@ -192,32 +200,22 @@ HTTPClient.prototype.sendSnapshot = function sendSnapshot(requestBody, config) {
|
|
|
192
200
|
return requestUtils.sendRequest({ method: 'post', options })
|
|
193
201
|
}
|
|
194
202
|
|
|
195
|
-
HTTPClient.prototype.
|
|
203
|
+
HTTPClient.prototype.getReportById = function getReportById(config, reportId) {
|
|
196
204
|
const options = _.cloneDeep(this.requestOptions)
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
HTTPClient.prototype.getSpecificReport = function getSpecificReport(
|
|
204
|
-
config,
|
|
205
|
-
reportId
|
|
206
|
-
) {
|
|
207
|
-
const options = _.cloneDeep(this.requestOptions)
|
|
208
|
-
let url = createSpecificReportUrl(config, reportId)
|
|
209
|
-
options.url = url
|
|
210
|
-
|
|
205
|
+
if (config.ignoreDev) {
|
|
206
|
+
options.url = createSpecificReportWithProdUrl(config, reportId)
|
|
207
|
+
} else {
|
|
208
|
+
options.url = createSpecificReportUrl(config, reportId)
|
|
209
|
+
}
|
|
211
210
|
return requestUtils.sendRequest({ method: 'get', options })
|
|
212
211
|
}
|
|
213
212
|
|
|
214
213
|
HTTPClient.prototype.getLibraryVulnerabilities = function getLibraryVulnerabilities(
|
|
215
|
-
|
|
216
|
-
|
|
214
|
+
config,
|
|
215
|
+
requestBody
|
|
217
216
|
) {
|
|
218
217
|
const options = _.cloneDeep(this.requestOptions)
|
|
219
|
-
|
|
220
|
-
options.url = url
|
|
218
|
+
options.url = createLibraryVulnerabilitiesUrl(config)
|
|
221
219
|
options.body = requestBody
|
|
222
220
|
|
|
223
221
|
return requestUtils.sendRequest({ method: 'put', options })
|
|
@@ -230,16 +228,16 @@ HTTPClient.prototype.getAppId = function getAppId(config) {
|
|
|
230
228
|
return requestUtils.sendRequest({ method: 'get', options })
|
|
231
229
|
}
|
|
232
230
|
|
|
233
|
-
HTTPClient.prototype.getDependencyTree = function getReport(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
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
|
+
// }
|
|
243
241
|
|
|
244
242
|
// serverless - lambda
|
|
245
243
|
function getServerlessHost(config = {}) {
|
|
@@ -317,6 +315,12 @@ HTTPClient.prototype.checkLibrary = function checkLibrary(data) {
|
|
|
317
315
|
return requestUtils.sendRequest({ method: 'post', options })
|
|
318
316
|
}
|
|
319
317
|
|
|
318
|
+
HTTPClient.prototype.getSbom = function getSbom(config) {
|
|
319
|
+
const options = _.cloneDeep(this.requestOptions)
|
|
320
|
+
options.url = createSbomCycloneDXUrl(config)
|
|
321
|
+
return requestUtils.sendRequest({ method: 'get', options })
|
|
322
|
+
}
|
|
323
|
+
|
|
320
324
|
// scan
|
|
321
325
|
const createGetScanIdURL = config => {
|
|
322
326
|
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/scans/`
|
|
@@ -370,20 +374,22 @@ function createLibraryVulnerabilitiesUrl(config) {
|
|
|
370
374
|
return `${config.host}/Contrast/api/ng/${config.organizationId}/libraries/artifactsByGroupNameVersion`
|
|
371
375
|
}
|
|
372
376
|
|
|
373
|
-
function
|
|
374
|
-
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}`
|
|
375
379
|
}
|
|
376
380
|
|
|
377
|
-
function
|
|
378
|
-
return
|
|
381
|
+
function createSpecificReportWithProdUrl(config, reportId) {
|
|
382
|
+
return createSpecificReportUrl(config, reportId).concat(
|
|
383
|
+
`?nodesToInclude=PROD`
|
|
384
|
+
)
|
|
379
385
|
}
|
|
380
386
|
|
|
381
387
|
function createDataUrl() {
|
|
382
388
|
return `https://ardy.contrastsecurity.com/production`
|
|
383
389
|
}
|
|
384
390
|
|
|
385
|
-
|
|
386
|
-
return `${
|
|
391
|
+
function createSbomCycloneDXUrl(config) {
|
|
392
|
+
return `${config.host}/Contrast/api/ng/${config.organizationId}/applications/${config.applicationId}/libraries/sbom/cyclonedx`
|
|
387
393
|
}
|
|
388
394
|
|
|
389
395
|
module.exports = HTTPClient
|
|
@@ -72,6 +72,7 @@ const badRequestError = (catalogue: boolean) => {
|
|
|
72
72
|
|
|
73
73
|
const forbiddenError = () => {
|
|
74
74
|
generalError('forbiddenRequestErrorHeader', 'forbiddenRequestErrorMessage')
|
|
75
|
+
process.exit(1)
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
const proxyError = () => {
|
|
@@ -104,7 +105,7 @@ const getErrorMessage = (header: string, message?: string) => {
|
|
|
104
105
|
const multiLine = message?.includes('\n')
|
|
105
106
|
let finalMessage = ''
|
|
106
107
|
|
|
107
|
-
// i18n split the line if it includes
|
|
108
|
+
// i18n split the line if it includes '\n'
|
|
108
109
|
if (multiLine) {
|
|
109
110
|
finalMessage = `\n${message}`
|
|
110
111
|
} else if (message) {
|
|
@@ -119,6 +120,31 @@ const generalError = (header: string, message?: string) => {
|
|
|
119
120
|
console.log(finalMessage)
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
const findCommandOnError = (unknownOptions: string[]) => {
|
|
124
|
+
const commandKeywords = {
|
|
125
|
+
auth: 'auth',
|
|
126
|
+
audit: 'audit',
|
|
127
|
+
scan: 'scan',
|
|
128
|
+
lambda: 'lambda',
|
|
129
|
+
config: 'config'
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const containsCommandKeyword = unknownOptions.some(
|
|
133
|
+
// @ts-ignore
|
|
134
|
+
command => commandKeywords[command]
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
if (containsCommandKeyword) {
|
|
138
|
+
const foundCommands = unknownOptions.filter(
|
|
139
|
+
// @ts-ignore
|
|
140
|
+
command => commandKeywords[command]
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
//return the first command found
|
|
144
|
+
return foundCommands[0]
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
122
148
|
export {
|
|
123
149
|
genericError,
|
|
124
150
|
unauthenticatedError,
|
|
@@ -130,5 +156,6 @@ export {
|
|
|
130
156
|
generalError,
|
|
131
157
|
getErrorMessage,
|
|
132
158
|
handleResponseErrors,
|
|
133
|
-
libraryAnalysisError
|
|
159
|
+
libraryAnalysisError,
|
|
160
|
+
findCommandOnError
|
|
134
161
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
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(updateMessageHidden: boolean) {
|
|
8
|
+
if (!updateMessageHidden) {
|
|
9
|
+
const latestCLIVersion = await latestVersion('@contrast/contrast')
|
|
10
|
+
|
|
11
|
+
if (semver.lt(APP_VERSION, latestCLIVersion)) {
|
|
12
|
+
const updateAvailableMessage = `Update available ${chalk.yellow(
|
|
13
|
+
APP_VERSION
|
|
14
|
+
)} → ${chalk.green(latestCLIVersion)}`
|
|
15
|
+
|
|
16
|
+
const npmUpdateAvailableCommand = `Run ${chalk.cyan(
|
|
17
|
+
'npm i @contrast/contrast -g'
|
|
18
|
+
)} to update via npm`
|
|
19
|
+
|
|
20
|
+
const homebrewUpdateAvailableCommand = `Run ${chalk.cyan(
|
|
21
|
+
'brew install contrastsecurity/tap/contrast'
|
|
22
|
+
)} to update via brew`
|
|
23
|
+
|
|
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
|
+
)
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function isCorrectNodeVersion(currentVersion: string) {
|
|
40
|
+
return semver.satisfies(currentVersion, '>=16.13.2 <17')
|
|
41
|
+
}
|
|
@@ -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.4'
|
|
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
|
}
|
package/src/constants/lambda.js
CHANGED
|
@@ -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: '
|
|
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:',
|