@contrast/contrast 1.0.18 → 1.0.20
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/audit/report/commonReportingFunctions.js +3 -4
- package/dist/audit/report/models/reportListModel.js +2 -1
- package/dist/audit/report/reportingFeature.js +1 -1
- package/dist/audit/report/utils/reportUtils.js +30 -11
- package/dist/cliConstants.js +1 -0
- package/dist/commands/audit/auditConfig.js +1 -2
- package/dist/commands/auth/auth.js +43 -7
- package/dist/commands/scan/sca/scaAnalysis.js +4 -2
- package/dist/common/HTTPClient.js +4 -4
- package/dist/common/errorHandling.js +13 -1
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +18 -2
- package/dist/scaAnalysis/common/auditReport.js +16 -60
- package/dist/scaAnalysis/common/commonReportingFunctionsSca.js +154 -0
- package/dist/scaAnalysis/common/models/ScaReportModel.js +45 -0
- package/dist/scaAnalysis/common/scaServicesUpload.js +4 -3
- package/dist/scaAnalysis/common/utils/reportUtilsSca.js +76 -0
- package/dist/scaAnalysis/java/analysis.js +1 -28
- package/dist/scaAnalysis/java/index.js +1 -13
- package/dist/scan/formatScanOutput.js +19 -13
- package/dist/utils/getConfig.js +1 -1
- package/dist/utils/paramsUtil/configStoreParams.js +1 -12
- package/dist/utils/paramsUtil/paramHandler.js +1 -7
- package/package.json +5 -1
- package/src/audit/report/commonReportingFunctions.js +7 -5
- package/src/audit/report/models/reportListModel.ts +12 -2
- package/src/audit/report/reportingFeature.ts +1 -1
- package/src/audit/report/utils/reportUtils.ts +4 -4
- package/src/cliConstants.js +1 -0
- package/src/commands/audit/auditConfig.js +1 -2
- package/src/commands/auth/auth.js +49 -7
- package/src/commands/scan/sca/scaAnalysis.js +7 -2
- package/src/common/HTTPClient.js +5 -4
- package/src/common/errorHandling.js +14 -1
- package/src/constants/constants.js +1 -1
- package/src/constants/locales.js +19 -2
- package/src/scaAnalysis/common/auditReport.js +25 -80
- package/src/scaAnalysis/common/commonReportingFunctionsSca.js +276 -0
- package/src/scaAnalysis/common/models/ScaReportModel.ts +81 -0
- package/src/scaAnalysis/common/scaServicesUpload.js +5 -3
- package/src/scaAnalysis/common/utils/reportUtilsSca.ts +123 -0
- package/src/scaAnalysis/java/analysis.js +1 -28
- package/src/scaAnalysis/java/index.js +1 -18
- package/src/scan/formatScanOutput.ts +28 -17
- package/src/utils/getConfig.ts +1 -2
- package/src/utils/paramsUtil/configStoreParams.js +1 -14
- package/src/utils/paramsUtil/paramHandler.js +1 -9
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { orderBy } from 'lodash'
|
|
2
|
+
import {
|
|
3
|
+
CRITICAL_COLOUR,
|
|
4
|
+
CRITICAL_PRIORITY,
|
|
5
|
+
HIGH_COLOUR,
|
|
6
|
+
HIGH_PRIORITY,
|
|
7
|
+
LOW_COLOUR,
|
|
8
|
+
LOW_PRIORITY,
|
|
9
|
+
MEDIUM_COLOUR,
|
|
10
|
+
MEDIUM_PRIORITY,
|
|
11
|
+
NOTE_COLOUR,
|
|
12
|
+
NOTE_PRIORITY
|
|
13
|
+
} from '../../../constants/constants'
|
|
14
|
+
import { ReportSeverityModel } from '../../../audit/report/models/reportSeverityModel'
|
|
15
|
+
import { SeverityCountModel } from '../../../audit/report/models/severityCountModel'
|
|
16
|
+
import {
|
|
17
|
+
ScaReportModel,
|
|
18
|
+
ScaReportVulnerabilityModel
|
|
19
|
+
} from '../models/ScaReportModel'
|
|
20
|
+
|
|
21
|
+
export function findHighestSeverityCVESca(
|
|
22
|
+
cveArray: ScaReportVulnerabilityModel[]
|
|
23
|
+
) {
|
|
24
|
+
const mappedToReportSeverityModels = cveArray.map(cve =>
|
|
25
|
+
findCVESeveritySca(cve)
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
//order and get first
|
|
29
|
+
return orderBy(mappedToReportSeverityModels, cve => cve?.priority)[0]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function orderByHighestPrioritySca(
|
|
33
|
+
reportSeverityModel: ReportSeverityModel[]
|
|
34
|
+
) {
|
|
35
|
+
return orderBy(reportSeverityModel, ['priority'], ['asc'])
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function findCVESeveritySca(
|
|
39
|
+
vulnerabilityModel: ScaReportVulnerabilityModel
|
|
40
|
+
) {
|
|
41
|
+
const { name } = vulnerabilityModel
|
|
42
|
+
|
|
43
|
+
if (
|
|
44
|
+
vulnerabilityModel.cvss3Severity === 'CRITICAL' ||
|
|
45
|
+
vulnerabilityModel.severity === 'CRITICAL'
|
|
46
|
+
) {
|
|
47
|
+
return new ReportSeverityModel(
|
|
48
|
+
'CRITICAL',
|
|
49
|
+
CRITICAL_PRIORITY,
|
|
50
|
+
CRITICAL_COLOUR,
|
|
51
|
+
name
|
|
52
|
+
)
|
|
53
|
+
} else if (
|
|
54
|
+
vulnerabilityModel.cvss3Severity === 'HIGH' ||
|
|
55
|
+
vulnerabilityModel.severity === 'HIGH'
|
|
56
|
+
) {
|
|
57
|
+
return new ReportSeverityModel('HIGH', HIGH_PRIORITY, HIGH_COLOUR, name)
|
|
58
|
+
} else if (
|
|
59
|
+
vulnerabilityModel.cvss3Severity === 'MEDIUM' ||
|
|
60
|
+
vulnerabilityModel.severity === 'MEDIUM'
|
|
61
|
+
) {
|
|
62
|
+
return new ReportSeverityModel(
|
|
63
|
+
'MEDIUM',
|
|
64
|
+
MEDIUM_PRIORITY,
|
|
65
|
+
MEDIUM_COLOUR,
|
|
66
|
+
name
|
|
67
|
+
)
|
|
68
|
+
} else if (
|
|
69
|
+
vulnerabilityModel.cvss3Severity === 'LOW' ||
|
|
70
|
+
vulnerabilityModel.severity === 'LOW'
|
|
71
|
+
) {
|
|
72
|
+
return new ReportSeverityModel('LOW', LOW_PRIORITY, LOW_COLOUR, name)
|
|
73
|
+
} else if (
|
|
74
|
+
vulnerabilityModel.cvss3Severity === 'NOTE' ||
|
|
75
|
+
vulnerabilityModel.severity === 'NOTE'
|
|
76
|
+
) {
|
|
77
|
+
return new ReportSeverityModel('NOTE', NOTE_PRIORITY, NOTE_COLOUR, name)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function convertGenericToTypedReportModelSca(reportArray: any) {
|
|
82
|
+
return reportArray.map((library: any) => {
|
|
83
|
+
return new ScaReportModel(library)
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function severityCountAllLibrariesSca(
|
|
88
|
+
vulnerableLibraries: ScaReportModel[],
|
|
89
|
+
severityCount: SeverityCountModel
|
|
90
|
+
) {
|
|
91
|
+
vulnerableLibraries.forEach(lib =>
|
|
92
|
+
severityCountAllCVEsSca(lib.vulnerabilities, severityCount)
|
|
93
|
+
)
|
|
94
|
+
return severityCount
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function severityCountAllCVEsSca(
|
|
98
|
+
cveArray: ScaReportVulnerabilityModel[],
|
|
99
|
+
severityCount: SeverityCountModel
|
|
100
|
+
) {
|
|
101
|
+
const severityCountInner = severityCount
|
|
102
|
+
cveArray.forEach(cve => severityCountSingleCVESca(cve, severityCountInner))
|
|
103
|
+
return severityCountInner
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function severityCountSingleCVESca(
|
|
107
|
+
cve: ScaReportVulnerabilityModel,
|
|
108
|
+
severityCount: SeverityCountModel
|
|
109
|
+
) {
|
|
110
|
+
if (cve.cvss3Severity === 'CRITICAL' || cve.severity === 'CRITICAL') {
|
|
111
|
+
severityCount.critical += 1
|
|
112
|
+
} else if (cve.cvss3Severity === 'HIGH' || cve.severity === 'HIGH') {
|
|
113
|
+
severityCount.high += 1
|
|
114
|
+
} else if (cve.cvss3Severity === 'MEDIUM' || cve.severity === 'MEDIUM') {
|
|
115
|
+
severityCount.medium += 1
|
|
116
|
+
} else if (cve.cvss3Severity === 'LOW' || cve.severity === 'LOW') {
|
|
117
|
+
severityCount.low += 1
|
|
118
|
+
} else if (cve.cvss3Severity === 'NOTE' || cve.severity === 'NOTE') {
|
|
119
|
+
severityCount.note += 1
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return severityCount
|
|
123
|
+
}
|
|
@@ -147,34 +147,7 @@ const getJavaBuildDeps = (config, files) => {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
const agreementPrompt = async config => {
|
|
151
|
-
const rl = readLine.createInterface({
|
|
152
|
-
input: process.stdin,
|
|
153
|
-
output: process.stdout
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
return new Promise((resolve, reject) => {
|
|
157
|
-
rl.question('❔ Do you want to continue? Type Y or N', async input => {
|
|
158
|
-
if (input.toLowerCase() === 'yes' || input.toLowerCase() === 'y') {
|
|
159
|
-
config.javaAgreement = paramHandler.setAgreement(true)
|
|
160
|
-
rl.close()
|
|
161
|
-
resolve(config)
|
|
162
|
-
} else if (input.toLowerCase() === 'no' || input.toLowerCase() === 'n') {
|
|
163
|
-
rl.close()
|
|
164
|
-
resolve(process.exit(1))
|
|
165
|
-
} else {
|
|
166
|
-
rl.close()
|
|
167
|
-
console.log('Invalid Input: Exiting')
|
|
168
|
-
resolve(process.exit(1))
|
|
169
|
-
}
|
|
170
|
-
})
|
|
171
|
-
}).catch(e => {
|
|
172
|
-
throw e
|
|
173
|
-
})
|
|
174
|
-
}
|
|
175
|
-
|
|
176
150
|
module.exports = {
|
|
177
151
|
getJavaBuildDeps,
|
|
178
|
-
determineProjectTypeAndCwd
|
|
179
|
-
agreementPrompt
|
|
152
|
+
determineProjectTypeAndCwd
|
|
180
153
|
}
|
|
@@ -4,16 +4,12 @@ const { createJavaTSMessage } = require('../common/formatMessage')
|
|
|
4
4
|
const {
|
|
5
5
|
parseDependenciesForSCAServices
|
|
6
6
|
} = require('../common/scaParserForGoAndJava')
|
|
7
|
-
const chalk = require('chalk')
|
|
8
|
-
const _ = require('lodash')
|
|
9
7
|
|
|
10
8
|
const javaAnalysis = async (config, languageFiles) => {
|
|
11
9
|
languageFiles.JAVA.forEach(file => {
|
|
12
10
|
file.replace('build.gradle.kts', 'build.gradle')
|
|
13
11
|
})
|
|
14
12
|
|
|
15
|
-
await getAgreement(config)
|
|
16
|
-
|
|
17
13
|
const javaDeps = buildJavaTree(config, languageFiles.JAVA)
|
|
18
14
|
|
|
19
15
|
if (config.experimental) {
|
|
@@ -23,24 +19,11 @@ const javaAnalysis = async (config, languageFiles) => {
|
|
|
23
19
|
}
|
|
24
20
|
}
|
|
25
21
|
|
|
26
|
-
const getAgreement = async config => {
|
|
27
|
-
console.log(chalk.bold('Java project detected'))
|
|
28
|
-
console.log(
|
|
29
|
-
'Java analysis uses maven / gradle which are potentially susceptible to command injection. Be sure that the code you are running Contrast CLI on is trusted before continuing.'
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
if (!process.env.CI && !config?.javaAgreement) {
|
|
33
|
-
return await analysis.agreementPrompt(config)
|
|
34
|
-
}
|
|
35
|
-
return config
|
|
36
|
-
}
|
|
37
|
-
|
|
38
22
|
const buildJavaTree = (config, files) => {
|
|
39
23
|
const javaBuildDeps = analysis.getJavaBuildDeps(config, files)
|
|
40
24
|
return parseBuildDeps(config, javaBuildDeps)
|
|
41
25
|
}
|
|
42
26
|
|
|
43
27
|
module.exports = {
|
|
44
|
-
javaAnalysis
|
|
45
|
-
getAgreement
|
|
28
|
+
javaAnalysis
|
|
46
29
|
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ScanResultsInstances,
|
|
3
|
-
ScanResultsModel
|
|
4
|
-
} from './models/scanResultsModel'
|
|
1
|
+
import { ScanResultsModel } from './models/scanResultsModel'
|
|
5
2
|
import i18n from 'i18n'
|
|
6
3
|
import chalk from 'chalk'
|
|
7
4
|
import { ResultContent } from './models/resultContentModel'
|
|
@@ -13,7 +10,8 @@ import {
|
|
|
13
10
|
HIGH_COLOUR,
|
|
14
11
|
LOW_COLOUR,
|
|
15
12
|
MEDIUM_COLOUR,
|
|
16
|
-
NOTE_COLOUR
|
|
13
|
+
NOTE_COLOUR,
|
|
14
|
+
supportedLanguagesScan
|
|
17
15
|
} from '../constants/constants'
|
|
18
16
|
import {
|
|
19
17
|
getSeverityCounts,
|
|
@@ -21,27 +19,28 @@ import {
|
|
|
21
19
|
} from '../audit/report/commonReportingFunctions'
|
|
22
20
|
|
|
23
21
|
export function formatScanOutput(scanResults: ScanResultsModel) {
|
|
24
|
-
const {
|
|
22
|
+
const { content } = scanResults.scanResultsInstances
|
|
23
|
+
const { language } = scanResults.scanDetail
|
|
25
24
|
|
|
26
|
-
const
|
|
27
|
-
if (
|
|
25
|
+
const severityCounts = getSeverityCounts(content)
|
|
26
|
+
if (content.length === 0) {
|
|
28
27
|
console.log(i18n.__('scanNoVulnerabilitiesFound'))
|
|
29
28
|
console.log(i18n.__('scanNoVulnerabilitiesFoundSecureCode'))
|
|
30
29
|
console.log(i18n.__('scanNoVulnerabilitiesFoundGoodWork'))
|
|
31
30
|
} else {
|
|
32
31
|
const message =
|
|
33
|
-
|
|
32
|
+
severityCounts.critical || severityCounts.high
|
|
34
33
|
? 'Here are your top priorities to fix'
|
|
35
34
|
: "No major issues, here's what we found"
|
|
36
35
|
console.log(chalk.bold(message))
|
|
37
36
|
console.log()
|
|
38
37
|
|
|
39
|
-
|
|
38
|
+
const defaultView = getDefaultView(content, language)
|
|
40
39
|
|
|
41
40
|
let count = 0
|
|
42
41
|
defaultView.forEach(entry => {
|
|
43
42
|
count++
|
|
44
|
-
|
|
43
|
+
const table = new Table({
|
|
45
44
|
chars: {
|
|
46
45
|
top: '',
|
|
47
46
|
'top-mid': '',
|
|
@@ -64,6 +63,7 @@ export function formatScanOutput(scanResults: ScanResultsModel) {
|
|
|
64
63
|
wordWrap: true,
|
|
65
64
|
colWidths: [12, 1, 100]
|
|
66
65
|
})
|
|
66
|
+
|
|
67
67
|
let learnRow: string[] = []
|
|
68
68
|
let adviceRow = []
|
|
69
69
|
const headerColour = chalk.hex(entry.colour)
|
|
@@ -107,9 +107,9 @@ export function formatScanOutput(scanResults: ScanResultsModel) {
|
|
|
107
107
|
console.log()
|
|
108
108
|
})
|
|
109
109
|
}
|
|
110
|
-
printVulnInfo(
|
|
110
|
+
printVulnInfo(severityCounts)
|
|
111
111
|
|
|
112
|
-
return
|
|
112
|
+
return severityCounts
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
export function formatLinks(objName: string, entry: any[]) {
|
|
@@ -124,7 +124,7 @@ export function formatLinks(objName: string, entry: any[]) {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
export function getDefaultView(content: ResultContent[]) {
|
|
127
|
+
export function getDefaultView(content: ResultContent[], language: string) {
|
|
128
128
|
const groupTypeResults = [] as GroupedResultsModel[]
|
|
129
129
|
|
|
130
130
|
content.forEach(resultEntry => {
|
|
@@ -136,8 +136,7 @@ export function getDefaultView(content: ResultContent[]) {
|
|
|
136
136
|
groupResultsObj.learn = resultEntry.learn
|
|
137
137
|
groupResultsObj.message = resultEntry.message?.text
|
|
138
138
|
? editVulName(resultEntry.message.text) +
|
|
139
|
-
|
|
140
|
-
getSourceLineNumber(resultEntry)
|
|
139
|
+
doAddSourceLineNumber(resultEntry, language)
|
|
141
140
|
: ''
|
|
142
141
|
groupResultsObj.codePath = getLocationsSyncInfo(resultEntry)
|
|
143
142
|
groupTypeResults.push(groupResultsObj)
|
|
@@ -146,9 +145,21 @@ export function getDefaultView(content: ResultContent[]) {
|
|
|
146
145
|
|
|
147
146
|
return sortBy(groupTypeResults, ['priority'])
|
|
148
147
|
}
|
|
148
|
+
|
|
149
|
+
export function doAddSourceLineNumber(
|
|
150
|
+
resultEntry: ResultContent,
|
|
151
|
+
language: string
|
|
152
|
+
) {
|
|
153
|
+
//only add source line num if not JS
|
|
154
|
+
return language !== supportedLanguagesScan.JAVASCRIPT
|
|
155
|
+
? ':' + getSourceLineNumber(resultEntry)
|
|
156
|
+
: ''
|
|
157
|
+
}
|
|
158
|
+
|
|
149
159
|
export function editVulName(message: string) {
|
|
150
160
|
return message.substring(message.indexOf(' in '))
|
|
151
161
|
}
|
|
162
|
+
|
|
152
163
|
export function getLocationsSyncInfo(resultEntry: ResultContent) {
|
|
153
164
|
const locationsMessage =
|
|
154
165
|
resultEntry.locations[0]?.physicalLocation?.artifactLocation?.uri || ''
|
|
@@ -165,7 +176,7 @@ export function getLocationsSyncInfo(resultEntry: ResultContent) {
|
|
|
165
176
|
export function getSourceLineNumber(resultEntry: ResultContent) {
|
|
166
177
|
const locationsLineNumber =
|
|
167
178
|
resultEntry.locations[0]?.physicalLocation?.region?.startLine || ''
|
|
168
|
-
|
|
179
|
+
const codeFlowLineNumber = getCodeFlowInfo(resultEntry)
|
|
169
180
|
|
|
170
181
|
return codeFlowLineNumber ? codeFlowLineNumber : locationsLineNumber
|
|
171
182
|
}
|
package/src/utils/getConfig.ts
CHANGED
|
@@ -8,7 +8,6 @@ type ContrastConfOptions = Partial<{
|
|
|
8
8
|
orgId: string
|
|
9
9
|
authHeader: string
|
|
10
10
|
numOfRuns: number
|
|
11
|
-
javaAgreement: boolean
|
|
12
11
|
}>
|
|
13
12
|
|
|
14
13
|
type ContrastConf = Conf<ContrastConfOptions>
|
|
@@ -29,7 +28,7 @@ const setConfigValues = (config: ContrastConf, values: ContrastConfOptions) => {
|
|
|
29
28
|
config.set('apiKey', values.apiKey)
|
|
30
29
|
config.set('organizationId', values.orgId)
|
|
31
30
|
config.set('authorization', values.authHeader)
|
|
32
|
-
values.host ? config.set('host', values.host) :
|
|
31
|
+
values.host ? config.set('host', values.host) : config.set('host', CE_URL)
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
export { localConfig, setConfigValues, ContrastConf, ContrastConfOptions }
|
|
@@ -16,17 +16,4 @@ const getAuth = () => {
|
|
|
16
16
|
return ContrastConfToUse
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
const ContrastConf = config.localConfig(APP_NAME, APP_VERSION)
|
|
21
|
-
let ContrastConfToUse = {}
|
|
22
|
-
ContrastConfToUse.javaAgreement = ContrastConf.get('javaAgreement')
|
|
23
|
-
return ContrastConfToUse
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const setAgreement = agreement => {
|
|
27
|
-
const ContrastConf = config.localConfig(APP_NAME, APP_VERSION)
|
|
28
|
-
ContrastConf.set('javaAgreement', agreement)
|
|
29
|
-
return agreement
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
module.exports = { getAuth, getAgreement, setAgreement }
|
|
19
|
+
module.exports = { getAuth }
|
|
@@ -21,12 +21,4 @@ const getAuth = params => {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
return configStoreParams.getAgreement()
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const setAgreement = answer => {
|
|
29
|
-
return configStoreParams.setAgreement(answer)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
module.exports = { getAuth, getAgreement, setAgreement }
|
|
24
|
+
module.exports = { getAuth }
|