@contrast/contrast 1.0.10 → 1.0.11
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/README.md +1 -1
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +39 -28
- package/dist/audit/languageAnalysisEngine/report/models/reportGuidanceModel.js +6 -0
- package/dist/audit/languageAnalysisEngine/report/models/reportOutputModel.js +1 -2
- package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +1 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +11 -7
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +1 -2
- package/dist/commands/audit/auditConfig.js +3 -3
- package/dist/commands/audit/processAudit.js +4 -2
- package/dist/commands/auth/auth.js +1 -1
- package/dist/commands/config/config.js +2 -2
- package/dist/commands/scan/processScan.js +11 -4
- package/dist/commands/scan/sca/scaAnalysis.js +10 -3
- package/dist/common/HTTPClient.js +9 -0
- package/dist/common/fail.js +66 -0
- package/dist/common/versionChecker.js +1 -1
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +6 -3
- package/dist/constants.js +39 -1
- package/dist/index.js +5 -2
- package/dist/scaAnalysis/common/scaParserForGoAndJava.js +32 -0
- package/dist/scaAnalysis/common/treeUpload.js +20 -5
- package/dist/scaAnalysis/dotnet/analysis.js +15 -3
- package/dist/scaAnalysis/go/goAnalysis.js +8 -2
- package/dist/scaAnalysis/java/analysis.js +10 -6
- package/dist/scaAnalysis/java/index.js +7 -1
- package/dist/scaAnalysis/java/javaBuildDepsParser.js +19 -3
- package/dist/scaAnalysis/python/analysis.js +43 -5
- package/dist/scaAnalysis/python/index.js +7 -2
- package/dist/scaAnalysis/ruby/analysis.js +14 -4
- package/dist/scan/formatScanOutput.js +6 -5
- package/dist/scan/populateProjectIdAndProjectName.js +5 -0
- package/dist/scan/scan.js +4 -0
- package/dist/scan/scanConfig.js +3 -3
- package/dist/scan/scanResults.js +39 -3
- package/dist/telemetry/telemetry.js +137 -0
- package/dist/utils/getConfig.js +2 -2
- package/dist/utils/parsedCLIOptions.js +3 -1
- package/dist/utils/requestUtils.js +7 -1
- package/package.json +1 -1
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +57 -39
- package/src/audit/languageAnalysisEngine/report/models/reportGuidanceModel.ts +5 -0
- package/src/audit/languageAnalysisEngine/report/models/reportOutputModel.ts +1 -7
- package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +2 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +15 -8
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +2 -2
- package/src/commands/audit/auditConfig.ts +10 -3
- package/src/commands/audit/processAudit.ts +16 -2
- package/src/commands/auth/auth.js +3 -1
- package/src/commands/config/config.js +4 -2
- package/src/commands/scan/processScan.js +18 -4
- package/src/commands/scan/sca/scaAnalysis.js +11 -3
- package/src/common/HTTPClient.js +14 -0
- package/src/common/fail.js +75 -0
- package/src/common/versionChecker.ts +1 -1
- package/src/constants/constants.js +1 -1
- package/src/constants/locales.js +8 -4
- package/src/constants.js +43 -1
- package/src/index.ts +17 -2
- package/src/scaAnalysis/common/scaParserForGoAndJava.js +41 -0
- package/src/scaAnalysis/common/treeUpload.js +21 -6
- package/src/scaAnalysis/dotnet/analysis.js +21 -3
- package/src/scaAnalysis/go/goAnalysis.js +9 -2
- package/src/scaAnalysis/java/analysis.js +11 -6
- package/src/scaAnalysis/java/index.js +9 -1
- package/src/scaAnalysis/java/javaBuildDepsParser.js +25 -6
- package/src/scaAnalysis/python/analysis.js +49 -5
- package/src/scaAnalysis/python/index.js +7 -2
- package/src/scaAnalysis/ruby/analysis.js +16 -4
- package/src/scan/formatScanOutput.ts +7 -5
- package/src/scan/populateProjectIdAndProjectName.js +5 -1
- package/src/scan/scan.ts +4 -0
- package/src/scan/scanConfig.js +5 -3
- package/src/scan/scanResults.js +46 -3
- package/src/telemetry/telemetry.ts +154 -0
- package/src/utils/getConfig.ts +4 -6
- package/src/utils/parsedCLIOptions.js +14 -1
- package/src/utils/requestUtils.js +8 -1
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
NOTE_COLOUR
|
|
30
30
|
} from '../../../constants/constants'
|
|
31
31
|
import Table from 'cli-table3'
|
|
32
|
+
import { ReportGuidanceModel } from './models/reportGuidanceModel'
|
|
32
33
|
|
|
33
34
|
export const createSummaryMessage = (
|
|
34
35
|
numberOfVulnerableLibraries: number,
|
|
@@ -160,7 +161,11 @@ export const printFormattedOutput = (
|
|
|
160
161
|
numOfCVEs
|
|
161
162
|
)
|
|
162
163
|
|
|
163
|
-
const advice = gatherRemediationAdvice(
|
|
164
|
+
const advice = gatherRemediationAdvice(
|
|
165
|
+
guidance,
|
|
166
|
+
libraryName,
|
|
167
|
+
libraryVersion
|
|
168
|
+
)
|
|
164
169
|
|
|
165
170
|
const body = buildBody(reportModel.cveArray, advice)
|
|
166
171
|
|
|
@@ -168,7 +173,6 @@ export const printFormattedOutput = (
|
|
|
168
173
|
|
|
169
174
|
table.push(
|
|
170
175
|
reportOutputModel.body.issueMessage,
|
|
171
|
-
reportOutputModel.body.issueMessageCves,
|
|
172
176
|
reportOutputModel.body.adviceMessage
|
|
173
177
|
)
|
|
174
178
|
|
|
@@ -203,18 +207,22 @@ export function buildHeader(
|
|
|
203
207
|
numOfCVEs > 1 ? 'vulnerabilities' : 'vulnerability'
|
|
204
208
|
const formattedHeaderNum = buildFormattedHeaderNum(contrastHeaderNum)
|
|
205
209
|
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
.
|
|
209
|
-
|
|
210
|
-
|
|
210
|
+
const headerColour = chalk.hex(highestSeverity.outputColour)
|
|
211
|
+
const headerNumAndSeverity = headerColour(
|
|
212
|
+
`${formattedHeaderNum} - [${highestSeverity.severity}]`
|
|
213
|
+
)
|
|
214
|
+
const libraryNameAndVersion = headerColour.bold(`${libraryName}-${version}`)
|
|
215
|
+
const vulnMessage = `${headerNumAndSeverity} ${libraryNameAndVersion}`
|
|
211
216
|
|
|
212
217
|
const introducesMessage = `introduces ${numOfCVEs} ${vulnerabilityPluralised}`
|
|
213
218
|
|
|
214
219
|
return new ReportOutputHeaderModel(vulnMessage, introducesMessage)
|
|
215
220
|
}
|
|
216
221
|
|
|
217
|
-
export function buildBody(
|
|
222
|
+
export function buildBody(
|
|
223
|
+
cveArray: ReportCVEModel[],
|
|
224
|
+
advice: ReportGuidanceModel
|
|
225
|
+
) {
|
|
218
226
|
const cveMessages: string[] = []
|
|
219
227
|
|
|
220
228
|
findCVESeveritiesAndOrderByHighestPriority(cveArray).forEach(
|
|
@@ -233,46 +241,40 @@ export function buildBody(cveArray: ReportCVEModel[], advice: any) {
|
|
|
233
241
|
|
|
234
242
|
const numAndSeverityType = getNumOfAndSeverityType(cveArray)
|
|
235
243
|
|
|
236
|
-
const issueMessage = [
|
|
237
|
-
|
|
238
|
-
|
|
244
|
+
const issueMessage = [
|
|
245
|
+
chalk.bold('Issue'),
|
|
246
|
+
':',
|
|
247
|
+
`${numAndSeverityType} ${cveMessages.join(', ')}`
|
|
248
|
+
]
|
|
239
249
|
|
|
240
250
|
//todo different advice based on remediationGuidance being available or now
|
|
241
251
|
// console.log(advice)
|
|
242
252
|
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
253
|
+
const minOrMax = advice.maximum ? advice.maximum : advice.minimum
|
|
254
|
+
const displayAdvice = minOrMax
|
|
255
|
+
? `Change to version ${chalk.bold(minOrMax)}`
|
|
256
|
+
: 'No recommendation is available according to our data. Upgrade to the latest stable is the best advice we can give.'
|
|
246
257
|
|
|
247
258
|
const adviceMessage = [chalk.bold('Advice'), ':', displayAdvice]
|
|
248
259
|
|
|
249
|
-
return new ReportOutputBodyModel(
|
|
250
|
-
issueMessage,
|
|
251
|
-
issueMessageCves,
|
|
252
|
-
adviceMessage
|
|
253
|
-
)
|
|
260
|
+
return new ReportOutputBodyModel(issueMessage, adviceMessage)
|
|
254
261
|
}
|
|
255
262
|
|
|
256
|
-
export function gatherRemediationAdvice(
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
263
|
+
export function gatherRemediationAdvice(
|
|
264
|
+
guidance: any,
|
|
265
|
+
libraryName: string,
|
|
266
|
+
libraryVersion: string
|
|
267
|
+
) {
|
|
268
|
+
const guidanceModel = new ReportGuidanceModel()
|
|
262
269
|
|
|
263
|
-
const data =
|
|
264
|
-
guidance[
|
|
265
|
-
reportModel.compositeKey.libraryName +
|
|
266
|
-
'@' +
|
|
267
|
-
reportModel.compositeKey.libraryVersion
|
|
268
|
-
]
|
|
270
|
+
const data = guidance[libraryName + '@' + libraryVersion]
|
|
269
271
|
|
|
270
272
|
if (data) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
+
guidanceModel.minimum = data.minUpgradeVersion
|
|
274
|
+
guidanceModel.maximum = data.maxUpgradeVersion
|
|
273
275
|
}
|
|
274
276
|
|
|
275
|
-
return
|
|
277
|
+
return guidanceModel
|
|
276
278
|
}
|
|
277
279
|
|
|
278
280
|
export function buildFormattedHeaderNum(contrastHeaderNum: number) {
|
|
@@ -285,11 +287,27 @@ export function getNumOfAndSeverityType(cveArray: ReportCVEModel[]) {
|
|
|
285
287
|
new SeverityCountModel()
|
|
286
288
|
)
|
|
287
289
|
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
const
|
|
291
|
-
const
|
|
292
|
-
|
|
290
|
+
const criticalNumCheck = critical > 0
|
|
291
|
+
|
|
292
|
+
const highNumCheck = high > 0
|
|
293
|
+
const highDivider = highNumCheck ? '|' : ''
|
|
294
|
+
|
|
295
|
+
const mediumNumCheck = medium > 0
|
|
296
|
+
const mediumDivider = mediumNumCheck ? '|' : ''
|
|
297
|
+
|
|
298
|
+
const lowNumCheck = low > 0
|
|
299
|
+
const lowDivider = lowNumCheck ? '|' : ''
|
|
300
|
+
|
|
301
|
+
const noteNumCheck = low > 0
|
|
302
|
+
const noteDivider = noteNumCheck ? '|' : ''
|
|
303
|
+
|
|
304
|
+
const criticalMessage = criticalNumCheck
|
|
305
|
+
? `${critical} Critical ${highDivider}`
|
|
306
|
+
: ''
|
|
307
|
+
const highMessage = highNumCheck ? `${high} High ${mediumDivider}` : ''
|
|
308
|
+
const mediumMessage = mediumNumCheck ? `${medium} Medium ${lowDivider}` : ''
|
|
309
|
+
const lowMessage = lowNumCheck ? `${low} Low ${noteDivider}` : ''
|
|
310
|
+
const noteMessage = noteNumCheck ? `${note} Note` : ''
|
|
293
311
|
|
|
294
312
|
//removes/trims whitespace to single spaces
|
|
295
313
|
return `${criticalMessage} ${highMessage} ${mediumMessage} ${lowMessage} ${noteMessage}`
|
|
@@ -20,16 +20,10 @@ export class ReportOutputHeaderModel {
|
|
|
20
20
|
|
|
21
21
|
export class ReportOutputBodyModel {
|
|
22
22
|
issueMessage: string[]
|
|
23
|
-
issueMessageCves: string[]
|
|
24
23
|
adviceMessage: string[]
|
|
25
24
|
|
|
26
|
-
constructor(
|
|
27
|
-
issueMessage: string[],
|
|
28
|
-
issueMessageCves: string[],
|
|
29
|
-
adviceMessage: string[]
|
|
30
|
-
) {
|
|
25
|
+
constructor(issueMessage: string[], adviceMessage: string[]) {
|
|
31
26
|
this.issueMessage = issueMessage
|
|
32
|
-
this.issueMessageCves = issueMessageCves
|
|
33
27
|
this.adviceMessage = adviceMessage
|
|
34
28
|
}
|
|
35
29
|
}
|
|
@@ -4,6 +4,7 @@ export class SeverityCountModel {
|
|
|
4
4
|
medium!: number
|
|
5
5
|
low!: number
|
|
6
6
|
note!: number
|
|
7
|
+
total!: number
|
|
7
8
|
|
|
8
9
|
//needed as default to stop NaN when new object constructed
|
|
9
10
|
constructor() {
|
|
@@ -12,6 +13,7 @@ export class SeverityCountModel {
|
|
|
12
13
|
this.medium = 0
|
|
13
14
|
this.low = 0
|
|
14
15
|
this.note = 0
|
|
16
|
+
this.total = 0
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
get getTotal(): number {
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
import i18n from 'i18n'
|
|
10
10
|
import chalk from 'chalk'
|
|
11
11
|
import * as constants from '../../../constants/constants'
|
|
12
|
+
import { SeverityCountModel } from './models/severityCountModel'
|
|
13
|
+
import * as common from '../../../common/fail'
|
|
12
14
|
|
|
13
15
|
export function convertKeysToStandardFormat(config: any, guidance: any) {
|
|
14
16
|
let convertedGuidance = guidance
|
|
@@ -72,6 +74,7 @@ export function formatVulnerabilityOutput(
|
|
|
72
74
|
String(0)
|
|
73
75
|
)
|
|
74
76
|
)
|
|
77
|
+
return [false, 0, [new SeverityCountModel()]]
|
|
75
78
|
} else {
|
|
76
79
|
let numberOfCves = 0
|
|
77
80
|
vulnerableLibraries.forEach(lib => (numberOfCves += lib.cveArray.length))
|
|
@@ -83,12 +86,13 @@ export function formatVulnerabilityOutput(
|
|
|
83
86
|
numberOfCves,
|
|
84
87
|
guidance
|
|
85
88
|
)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
let severityCount = new SeverityCountModel()
|
|
90
|
+
severityCount = severityCountAllLibraries(
|
|
91
|
+
vulnerableLibraries,
|
|
92
|
+
severityCount
|
|
93
|
+
)
|
|
94
|
+
severityCount.total = severityCount.getTotal
|
|
95
|
+
return [hasSomeVulnerabilitiesReported, numberOfCves, severityCount]
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
98
|
|
|
@@ -97,8 +101,7 @@ export async function vulnerabilityReportV2(config: any, reportId: string) {
|
|
|
97
101
|
const reportResponse = await getReport(config, reportId)
|
|
98
102
|
|
|
99
103
|
if (reportResponse !== undefined) {
|
|
100
|
-
|
|
101
|
-
formatVulnerabilityOutput(
|
|
104
|
+
let output = formatVulnerabilityOutput(
|
|
102
105
|
reportResponse.vulnerabilities,
|
|
103
106
|
config.applicationId,
|
|
104
107
|
config,
|
|
@@ -106,5 +109,9 @@ export async function vulnerabilityReportV2(config: any, reportId: string) {
|
|
|
106
109
|
? reportResponse.remediationGuidance
|
|
107
110
|
: {}
|
|
108
111
|
)
|
|
112
|
+
|
|
113
|
+
if (config.fail) {
|
|
114
|
+
common.processFail(config, output[2])
|
|
115
|
+
}
|
|
109
116
|
}
|
|
110
117
|
}
|
|
@@ -75,9 +75,9 @@ export function convertGenericToTypedLibraryVulns(libraries: any) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
export function severityCountAllLibraries(
|
|
78
|
-
vulnerableLibraries: ReportLibraryModel[]
|
|
78
|
+
vulnerableLibraries: ReportLibraryModel[],
|
|
79
|
+
severityCount: SeverityCountModel
|
|
79
80
|
) {
|
|
80
|
-
const severityCount = new SeverityCountModel()
|
|
81
81
|
vulnerableLibraries.forEach(lib =>
|
|
82
82
|
severityCountAllCVEs(lib.cveArray, severityCount)
|
|
83
83
|
)
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import paramHandler from '../../utils/paramsUtil/paramHandler'
|
|
2
2
|
import constants from '../../constants'
|
|
3
|
-
import
|
|
3
|
+
import { getCommandLineArgsCustom } from '../../utils/parsedCLIOptions'
|
|
4
|
+
import { ContrastConf } from '../../utils/getConfig'
|
|
4
5
|
|
|
5
|
-
export const getAuditConfig = (
|
|
6
|
-
|
|
6
|
+
export const getAuditConfig = async (
|
|
7
|
+
contrastConf: ContrastConf,
|
|
8
|
+
command: string,
|
|
9
|
+
argv: string[]
|
|
10
|
+
): Promise<{ [key: string]: string }> => {
|
|
11
|
+
const auditParameters = await getCommandLineArgsCustom(
|
|
12
|
+
contrastConf,
|
|
13
|
+
command,
|
|
7
14
|
argv,
|
|
8
15
|
constants.commandLineDefinitions.auditOptionDefinitions
|
|
9
16
|
)
|
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
import { getAuditConfig } from './auditConfig'
|
|
2
2
|
import { auditUsageGuide } from './help'
|
|
3
3
|
import { processSca } from '../scan/sca/scaAnalysis'
|
|
4
|
+
import { sendTelemetryConfigAsObject } from '../../telemetry/telemetry'
|
|
5
|
+
import { ContrastConf } from '../../utils/getConfig'
|
|
4
6
|
|
|
5
7
|
export type parameterInput = string[]
|
|
6
8
|
|
|
7
|
-
export const processAudit = async (
|
|
9
|
+
export const processAudit = async (
|
|
10
|
+
contrastConf: ContrastConf,
|
|
11
|
+
argv: parameterInput
|
|
12
|
+
) => {
|
|
8
13
|
if (argv.indexOf('--help') != -1) {
|
|
9
14
|
printHelpMessage()
|
|
10
15
|
process.exit(0)
|
|
11
16
|
}
|
|
12
|
-
|
|
17
|
+
|
|
18
|
+
const config = await getAuditConfig(contrastConf, 'audit', argv)
|
|
13
19
|
await processSca(config)
|
|
20
|
+
await sendTelemetryConfigAsObject(
|
|
21
|
+
config,
|
|
22
|
+
'audit',
|
|
23
|
+
argv,
|
|
24
|
+
'SUCCESS',
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
config.language
|
|
27
|
+
)
|
|
14
28
|
}
|
|
15
29
|
|
|
16
30
|
const printHelpMessage = () => {
|
|
@@ -16,7 +16,9 @@ const constants = require('../../constants')
|
|
|
16
16
|
const commandLineUsage = require('command-line-usage')
|
|
17
17
|
|
|
18
18
|
const processAuth = async (argv, config) => {
|
|
19
|
-
let authParams = parsedCLIOptions.getCommandLineArgsCustom(
|
|
19
|
+
let authParams = await parsedCLIOptions.getCommandLineArgsCustom(
|
|
20
|
+
config,
|
|
21
|
+
'auth',
|
|
20
22
|
argv,
|
|
21
23
|
constants.commandLineDefinitions.authOptionDefinitions
|
|
22
24
|
)
|
|
@@ -3,9 +3,11 @@ const constants = require('../../constants')
|
|
|
3
3
|
const commandLineUsage = require('command-line-usage')
|
|
4
4
|
const i18n = require('i18n')
|
|
5
5
|
|
|
6
|
-
const processConfig = (argv, config) => {
|
|
6
|
+
const processConfig = async (argv, config) => {
|
|
7
7
|
try {
|
|
8
|
-
let configParams = parsedCLIOptions.getCommandLineArgsCustom(
|
|
8
|
+
let configParams = await parsedCLIOptions.getCommandLineArgsCustom(
|
|
9
|
+
config,
|
|
10
|
+
'config',
|
|
9
11
|
argv,
|
|
10
12
|
constants.commandLineDefinitions.configOptionDefinitions
|
|
11
13
|
)
|
|
@@ -4,23 +4,37 @@ const { saveScanFile } = require('../../utils/saveFile')
|
|
|
4
4
|
const { ScanResultsModel } = require('../../scan/models/scanResultsModel')
|
|
5
5
|
const { formatScanOutput } = require('../../scan/formatScanOutput')
|
|
6
6
|
const { processSca } = require('./sca/scaAnalysis')
|
|
7
|
+
const common = require('../../common/fail')
|
|
8
|
+
const { sendTelemetryConfigAsObject } = require('../../telemetry/telemetry')
|
|
7
9
|
|
|
8
|
-
const processScan = async
|
|
9
|
-
let config = scanConfig.getScanConfig(
|
|
10
|
+
const processScan = async (contrastConf, argv) => {
|
|
11
|
+
let config = await scanConfig.getScanConfig(contrastConf, 'scan', argv)
|
|
12
|
+
let output = undefined
|
|
10
13
|
//try SCA analysis first
|
|
11
14
|
if (config.experimental) {
|
|
12
|
-
await processSca(config)
|
|
15
|
+
await processSca(config, argv)
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
let scanResults = new ScanResultsModel(await startScan(config))
|
|
19
|
+
await sendTelemetryConfigAsObject(
|
|
20
|
+
config,
|
|
21
|
+
'scan',
|
|
22
|
+
argv,
|
|
23
|
+
'SUCCESS',
|
|
24
|
+
scanResults.scanDetail.language
|
|
25
|
+
)
|
|
16
26
|
|
|
17
27
|
if (scanResults.scanResultsInstances !== undefined) {
|
|
18
|
-
formatScanOutput(scanResults)
|
|
28
|
+
output = formatScanOutput(scanResults)
|
|
19
29
|
}
|
|
20
30
|
|
|
21
31
|
if (config.save !== undefined) {
|
|
22
32
|
await saveScanFile(config, scanResults)
|
|
23
33
|
}
|
|
34
|
+
|
|
35
|
+
if (config.fail) {
|
|
36
|
+
common.processFail(config, output)
|
|
37
|
+
}
|
|
24
38
|
}
|
|
25
39
|
|
|
26
40
|
module.exports = {
|
|
@@ -24,16 +24,22 @@ const {
|
|
|
24
24
|
} = require('../../../audit/languageAnalysisEngine/report/reportingFeature')
|
|
25
25
|
const auditSave = require('../../../audit/save')
|
|
26
26
|
const { dotNetAnalysis } = require('../../../scaAnalysis/dotnet')
|
|
27
|
+
const { auditUsageGuide } = require('../../audit/help')
|
|
27
28
|
const rootFile = require('../../../audit/languageAnalysisEngine/getProjectRootFilenames')
|
|
28
29
|
const path = require('path')
|
|
29
30
|
const processSca = async config => {
|
|
30
31
|
const startTime = performance.now()
|
|
31
32
|
let filesFound
|
|
32
33
|
|
|
34
|
+
if (config.help) {
|
|
35
|
+
console.log(auditUsageGuide)
|
|
36
|
+
process.exit(0)
|
|
37
|
+
}
|
|
38
|
+
|
|
33
39
|
const projectStats = await rootFile.getProjectStats(config.file)
|
|
34
40
|
let pathWithFile = projectStats.isFile()
|
|
35
41
|
|
|
36
|
-
|
|
42
|
+
config.fileName = config.file
|
|
37
43
|
config.file = pathWithFile
|
|
38
44
|
? rootFile.getDirectoryFromPathGiven(config.file).concat('/')
|
|
39
45
|
: config.file
|
|
@@ -42,7 +48,7 @@ const processSca = async config => {
|
|
|
42
48
|
|
|
43
49
|
if (filesFound.length > 1 && pathWithFile) {
|
|
44
50
|
filesFound = filesFound.filter(i =>
|
|
45
|
-
Object.values(i)[0].includes(path.basename(fileName))
|
|
51
|
+
Object.values(i)[0].includes(path.basename(config.fileName))
|
|
46
52
|
)
|
|
47
53
|
}
|
|
48
54
|
|
|
@@ -127,7 +133,9 @@ const processSca = async config => {
|
|
|
127
133
|
throw new Error()
|
|
128
134
|
} else {
|
|
129
135
|
throw new Error(
|
|
130
|
-
|
|
136
|
+
`multiple language files detected \n` +
|
|
137
|
+
JSON.stringify(filesFound) +
|
|
138
|
+
`\nplease use --file to audit one language only. Example: contrast audit --file package-lock.json`
|
|
131
139
|
)
|
|
132
140
|
}
|
|
133
141
|
}
|
package/src/common/HTTPClient.js
CHANGED
|
@@ -346,6 +346,16 @@ HTTPClient.prototype.getLatestVersion = function getLatestVersion() {
|
|
|
346
346
|
return requestUtils.sendRequest({ method: 'get', options })
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
+
HTTPClient.prototype.postTelemetry = function postTelemetry(
|
|
350
|
+
config,
|
|
351
|
+
requestBody
|
|
352
|
+
) {
|
|
353
|
+
const options = _.cloneDeep(this.requestOptions)
|
|
354
|
+
options.url = createTelemetryEventUrl(config)
|
|
355
|
+
options.body = requestBody
|
|
356
|
+
return requestUtils.sendRequest({ method: 'post', options })
|
|
357
|
+
}
|
|
358
|
+
|
|
349
359
|
// analytics
|
|
350
360
|
|
|
351
361
|
HTTPClient.prototype.postAnalyticsFunction = function (config, provider, body) {
|
|
@@ -439,6 +449,10 @@ function createSbomUrl(config, type) {
|
|
|
439
449
|
return `${config.host}/Contrast/api/ng/${config.organizationId}/applications/${config.applicationId}/libraries/sbom/${type}`
|
|
440
450
|
}
|
|
441
451
|
|
|
452
|
+
function createTelemetryEventUrl(config) {
|
|
453
|
+
return `${config.host}/Contrast/api/sast/organizations/${config.organizationId}/cli`
|
|
454
|
+
}
|
|
455
|
+
|
|
442
456
|
module.exports = HTTPClient
|
|
443
457
|
module.exports.pollForAuthUrl = pollForAuthUrl
|
|
444
458
|
module.exports.getServerlessHost = getServerlessHost
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const i18n = require('i18n')
|
|
2
|
+
|
|
3
|
+
const processFail = (config, reportResults) => {
|
|
4
|
+
if (config.severity !== undefined) {
|
|
5
|
+
if (
|
|
6
|
+
reportResults[config.severity] !== undefined &&
|
|
7
|
+
isSeverityViolation(config.severity, reportResults)
|
|
8
|
+
) {
|
|
9
|
+
failPipeline('failSeverityOptionErrorMessage')
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (config.severity === undefined && reportResults.total > 0) {
|
|
14
|
+
failPipeline('failThresholdOptionErrorMessage')
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const isSeverityViolation = (severity, reportResults) => {
|
|
19
|
+
let count = 0
|
|
20
|
+
switch (severity) {
|
|
21
|
+
case 'critical':
|
|
22
|
+
count += reportResults.critical
|
|
23
|
+
break
|
|
24
|
+
case 'high':
|
|
25
|
+
count += reportResults.high + reportResults.critical
|
|
26
|
+
break
|
|
27
|
+
case 'medium':
|
|
28
|
+
count += reportResults.medium + reportResults.low + reportResults.critical
|
|
29
|
+
break
|
|
30
|
+
case 'low':
|
|
31
|
+
count +=
|
|
32
|
+
reportResults.high + reportResults.critical + reportResults.medium
|
|
33
|
+
break
|
|
34
|
+
case 'note':
|
|
35
|
+
if (reportResults.note == reportResults.total) {
|
|
36
|
+
count = 0
|
|
37
|
+
} else {
|
|
38
|
+
count = reportResults.total
|
|
39
|
+
}
|
|
40
|
+
break
|
|
41
|
+
default:
|
|
42
|
+
count = 0
|
|
43
|
+
}
|
|
44
|
+
return count > 0
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const failPipeline = (message = '') => {
|
|
48
|
+
console.log(
|
|
49
|
+
'\n ******************************** ' +
|
|
50
|
+
i18n.__('snapshotFailureHeader') +
|
|
51
|
+
' *********************************\n' +
|
|
52
|
+
i18n.__(message)
|
|
53
|
+
)
|
|
54
|
+
process.exit(1)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const parseSeverity = severity => {
|
|
58
|
+
const severities = ['NOTE', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL']
|
|
59
|
+
if (severities.includes(severity.toUpperCase())) {
|
|
60
|
+
return severity.toLowerCase()
|
|
61
|
+
} else {
|
|
62
|
+
console.log(
|
|
63
|
+
severity +
|
|
64
|
+
' Not recognised as a severity type please use LOW, MEDIUM, HIGH, CRITICAL, NOTE'
|
|
65
|
+
)
|
|
66
|
+
return undefined
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = {
|
|
71
|
+
failPipeline,
|
|
72
|
+
processFail,
|
|
73
|
+
isSeverityViolation,
|
|
74
|
+
parseSeverity
|
|
75
|
+
}
|
|
@@ -20,7 +20,7 @@ const getLatestVersion = async (config: any) => {
|
|
|
20
20
|
|
|
21
21
|
// @ts-ignore
|
|
22
22
|
export async function findLatestCLIVersion(config: ContrastConf) {
|
|
23
|
-
const messageHidden = config.get('
|
|
23
|
+
const messageHidden = config.get('isCI') as boolean
|
|
24
24
|
|
|
25
25
|
if (!messageHidden) {
|
|
26
26
|
let latestCLIVersion: string = await getLatestVersion(config)
|
package/src/constants/locales.js
CHANGED
|
@@ -121,9 +121,11 @@ const en_locales = () => {
|
|
|
121
121
|
'The name of the application cataloged by Contrast UI',
|
|
122
122
|
constantsCatalogueApplication:
|
|
123
123
|
'Provide this if you want to catalogue an application',
|
|
124
|
+
failOptionErrorMessage:
|
|
125
|
+
' FAIL - CVEs have been detected that match at least the cve_severity option specified.',
|
|
124
126
|
constantsLanguage:
|
|
125
127
|
'Valid values are JAVA, DOTNET, NODE, PYTHON and RUBY. If there are multiple project configuration files in the project_path, language is also required. Also, provide this when cataloguing an application',
|
|
126
|
-
constantsFilePath: `
|
|
128
|
+
constantsFilePath: `Specify a directory or the file where dependencies are declared. (By default, CodeSec will search for project files in the current directory.)`,
|
|
127
129
|
constantsSilent: 'Silences JSON output.',
|
|
128
130
|
constantsAppGroups:
|
|
129
131
|
'Assign your application to one or more pre-existing groups when using the catalogue command. Group lists should be comma separated.',
|
|
@@ -142,8 +144,9 @@ const en_locales = () => {
|
|
|
142
144
|
constantsReport: 'Display vulnerability information for this application',
|
|
143
145
|
constantsFail:
|
|
144
146
|
'Set the process to fail if this option is set in combination with --cve_severity.',
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
failThresholdOptionErrorMessage: 'More than 0 vulnerabilities found',
|
|
148
|
+
failSeverityOptionErrorMessage:
|
|
149
|
+
' FAIL - Results detected vulnerabilities over accepted severity level',
|
|
147
150
|
constantsSeverity:
|
|
148
151
|
'Allows the user to report libraries with vulnerabilities above a chosen severity level. For example, cve_severity medium only reports libraries with vulnerabilities at medium or higher severity. Values for level are high, medium or low.',
|
|
149
152
|
constantsCount: 'The number of CVEs that must be exceeded to fail a build',
|
|
@@ -414,7 +417,8 @@ const en_locales = () => {
|
|
|
414
417
|
auditOptionsSaveDescription:
|
|
415
418
|
'Generate and save an SBOM (Software Bill of Materials)\n',
|
|
416
419
|
auditOptionsSaveOptionsDescription:
|
|
417
|
-
'Valid options are: spdx
|
|
420
|
+
'Valid options are: --save spdx and --save cyclonedx (CycloneDX is the default format.)',
|
|
421
|
+
exceededFreeTier: `It looks like you are really loving CodeSec! \nYou have reached the monthly scan limit on the FREE tier. \nPlease contact sales@contrastsecurity.com to upgrade.`,
|
|
418
422
|
scanNotCompleted:
|
|
419
423
|
'Scan not completed. Check for framework and language support here: %s',
|
|
420
424
|
auditNotCompleted: 'audit not completed. Please try again',
|