@contrast/contrast 1.0.3 → 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 +1 -0
- package/README.md +20 -14
- package/dist/audit/languageAnalysisEngine/{langugageAnalysisFactory.js → languageAnalysisFactory.js} +2 -12
- 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/scan/processScan.js +4 -3
- package/dist/common/HTTPClient.js +19 -26
- package/dist/common/versionChecker.js +14 -12
- package/dist/constants/constants.js +1 -1
- package/dist/constants/lambda.js +3 -1
- package/dist/constants/locales.js +17 -10
- package/dist/constants.js +5 -1
- package/dist/index.js +2 -2
- package/dist/lambda/help.js +22 -14
- package/dist/lambda/lambda.js +6 -0
- 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/scan.js +90 -95
- package/dist/scan/scanConfig.js +1 -1
- package/dist/utils/getConfig.js +3 -0
- package/package.json +2 -2
- package/src/audit/languageAnalysisEngine/{langugageAnalysisFactory.js → languageAnalysisFactory.js} +2 -16
- 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/scan/processScan.js +4 -6
- package/src/common/HTTPClient.js +31 -38
- package/src/common/errorHandling.ts +0 -1
- package/src/common/versionChecker.ts +24 -22
- package/src/constants/constants.js +1 -1
- package/src/constants/lambda.js +3 -1
- package/src/constants/locales.js +20 -10
- package/src/constants.js +7 -1
- package/src/index.ts +2 -3
- package/src/lambda/help.ts +22 -14
- package/src/lambda/lambda.ts +8 -0
- 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/scan.ts +192 -0
- package/src/scan/scanConfig.js +1 -1
- package/src/scan/scanController.js +2 -0
- package/src/utils/getConfig.ts +10 -0
- package/dist/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +0 -17
- package/dist/audit/languageAnalysisEngine/report/newReportingFeature.js +0 -81
- 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/scan/scan.js +0 -195
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
type Importance = 'important' | 'essential'
|
|
2
|
+
|
|
3
|
+
interface ArtifactLocation {
|
|
4
|
+
uri: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
interface Region {
|
|
8
|
+
startLine: number
|
|
9
|
+
snippet: Snippet
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface Snippet {
|
|
13
|
+
text: string
|
|
14
|
+
rendered: Rendered
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface Rendered {
|
|
18
|
+
text: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface PhysicalLocation {
|
|
22
|
+
artifactLocation: ArtifactLocation
|
|
23
|
+
region: Region
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface LogicalLocation {
|
|
27
|
+
fullyQualifiedName: string
|
|
28
|
+
name: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface Location {
|
|
32
|
+
physicalLocation: PhysicalLocation
|
|
33
|
+
logicalLocations?: LogicalLocation[]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ThreadFlowLocation {
|
|
37
|
+
importance: Importance
|
|
38
|
+
location: Location
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface ThreadFlow {
|
|
42
|
+
locations: ThreadFlowLocation[]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface Message {
|
|
46
|
+
text: string
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface CodeFlow {
|
|
50
|
+
message: Message
|
|
51
|
+
threadFlows: ThreadFlow[]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface ResultContent {
|
|
55
|
+
message: {text: string};
|
|
56
|
+
id: string
|
|
57
|
+
organizationId: string
|
|
58
|
+
projectId: string
|
|
59
|
+
firstCreatedTime: string
|
|
60
|
+
ruleId: string
|
|
61
|
+
codeFlows: CodeFlow[]
|
|
62
|
+
lastSeenTime: string
|
|
63
|
+
locations: Location[]
|
|
64
|
+
name: string
|
|
65
|
+
description: string
|
|
66
|
+
recommendation: string | null
|
|
67
|
+
risk: string | null
|
|
68
|
+
category: string
|
|
69
|
+
confidence: string
|
|
70
|
+
standards: { [key: string]: string[] }
|
|
71
|
+
cwe: string[]
|
|
72
|
+
owasp: string[]
|
|
73
|
+
reference: string[]
|
|
74
|
+
sink: string
|
|
75
|
+
detailsTrigger: string
|
|
76
|
+
type: RuleType
|
|
77
|
+
source: string
|
|
78
|
+
severity: Severity
|
|
79
|
+
advice: string
|
|
80
|
+
learn: string[]
|
|
81
|
+
issue: string
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type Severity = 'critical' | 'high' | 'medium' | 'low' | 'note'
|
|
85
|
+
|
|
86
|
+
export type RuleType = 'DATA_FLOW' | 'CRYPTO' | 'CONFIG' | 'DEFAULT'
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ResultContent } from './resultContentModel'
|
|
2
|
+
|
|
3
|
+
export class ScanResultsModel {
|
|
4
|
+
projectOverview: ProjectOverview
|
|
5
|
+
scanDetail: ScanDetail
|
|
6
|
+
scanResultsInstances: ScanResultsInstances
|
|
7
|
+
|
|
8
|
+
constructor(scan: any) {
|
|
9
|
+
this.projectOverview = scan.projectOverview as ProjectOverview
|
|
10
|
+
this.scanDetail = scan.scanDetail as ScanDetail
|
|
11
|
+
this.scanResultsInstances = scan.scanResultsInstances as ScanResultsInstances
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ProjectOverview {
|
|
16
|
+
id: string
|
|
17
|
+
organizationId: string
|
|
18
|
+
name: string
|
|
19
|
+
archived: boolean
|
|
20
|
+
language: string
|
|
21
|
+
critical: number
|
|
22
|
+
high: number
|
|
23
|
+
medium: number
|
|
24
|
+
low: number
|
|
25
|
+
note: number
|
|
26
|
+
lastScanTime: string
|
|
27
|
+
completedScans: number
|
|
28
|
+
lastScanId: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ScanDetail {
|
|
32
|
+
critical: number
|
|
33
|
+
high: number
|
|
34
|
+
medium: number
|
|
35
|
+
low: number
|
|
36
|
+
note: number
|
|
37
|
+
id: string
|
|
38
|
+
organizationId: string
|
|
39
|
+
projectId: string
|
|
40
|
+
codeArtifactId: string
|
|
41
|
+
status: string
|
|
42
|
+
createdTime: string
|
|
43
|
+
startedTime: string
|
|
44
|
+
completedTime: string
|
|
45
|
+
language: string
|
|
46
|
+
label: string
|
|
47
|
+
errorMessage: string
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ScanResultsInstances {
|
|
51
|
+
content: ResultContent[]
|
|
52
|
+
}
|
package/src/scan/scan.ts
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import commonApi from '../utils/commonApi.js'
|
|
2
|
+
import fileUtils from '../scan/fileUtils'
|
|
3
|
+
import i18n from 'i18n'
|
|
4
|
+
import oraWrapper from '../utils/oraWrapper'
|
|
5
|
+
import chalk from 'chalk'
|
|
6
|
+
import { ProjectOverview, ScanResultsModel } from './models/scanResultsModel'
|
|
7
|
+
import { Location, ResultContent } from './models/resultContentModel'
|
|
8
|
+
import { GroupedResultsModel } from './models/groupedResultsModel'
|
|
9
|
+
|
|
10
|
+
export const allowedFileTypes = ['.jar', '.war', '.js', '.zip', '.exe']
|
|
11
|
+
|
|
12
|
+
export const isFileAllowed = (scanOption: string) => {
|
|
13
|
+
let valid = false
|
|
14
|
+
allowedFileTypes.forEach(fileType => {
|
|
15
|
+
if (scanOption.endsWith(fileType)) {
|
|
16
|
+
valid = true
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
return valid
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const sendScan = async (config: any) => {
|
|
23
|
+
if (!isFileAllowed(config.file)) {
|
|
24
|
+
console.log(i18n.__('scanErrorFileMessage'))
|
|
25
|
+
process.exit(9)
|
|
26
|
+
} else {
|
|
27
|
+
fileUtils.checkFilePermissions(config.file)
|
|
28
|
+
const client = commonApi.getHttpClient(config)
|
|
29
|
+
|
|
30
|
+
const startUploadSpinner = oraWrapper.returnOra(i18n.__('uploadingScan'))
|
|
31
|
+
oraWrapper.startSpinner(startUploadSpinner)
|
|
32
|
+
|
|
33
|
+
return await client
|
|
34
|
+
.sendArtifact(config)
|
|
35
|
+
.then(res => {
|
|
36
|
+
if (res.statusCode === 201) {
|
|
37
|
+
oraWrapper.succeedSpinner(
|
|
38
|
+
startUploadSpinner,
|
|
39
|
+
i18n.__('uploadingScanSuccessful')
|
|
40
|
+
)
|
|
41
|
+
if (config.verbose) {
|
|
42
|
+
console.log(i18n.__('responseMessage', res.body))
|
|
43
|
+
}
|
|
44
|
+
return res.body.id
|
|
45
|
+
} else {
|
|
46
|
+
if (config.debug) {
|
|
47
|
+
console.log(res.statusCode)
|
|
48
|
+
console.log(config)
|
|
49
|
+
}
|
|
50
|
+
oraWrapper.failSpinner(
|
|
51
|
+
startUploadSpinner,
|
|
52
|
+
i18n.__('uploadingScanFail')
|
|
53
|
+
)
|
|
54
|
+
if (res.statusCode === 403) {
|
|
55
|
+
console.log(i18n.__('permissionsError'))
|
|
56
|
+
process.exit(1)
|
|
57
|
+
}
|
|
58
|
+
console.log(i18n.__('genericServiceError', res.statusCode))
|
|
59
|
+
process.exit(1)
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
.catch(err => {
|
|
63
|
+
console.log(err)
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function formatScanOutput(scanResults: ScanResultsModel) {
|
|
69
|
+
const { projectOverview, scanResultsInstances } = scanResults
|
|
70
|
+
|
|
71
|
+
if (scanResultsInstances.content.length === 0) {
|
|
72
|
+
console.log(i18n.__('scanNoVulnerabilitiesFound'))
|
|
73
|
+
} else {
|
|
74
|
+
const message =
|
|
75
|
+
projectOverview.critical || projectOverview.high
|
|
76
|
+
? 'Here are your top priorities to fix'
|
|
77
|
+
: "No major issues, here's what we found"
|
|
78
|
+
console.log(chalk.bold(message))
|
|
79
|
+
console.log()
|
|
80
|
+
|
|
81
|
+
const groups = getGroups(scanResultsInstances.content)
|
|
82
|
+
|
|
83
|
+
groups.forEach(entry => {
|
|
84
|
+
console.log(
|
|
85
|
+
chalk.bold(
|
|
86
|
+
`[ ${entry.severity} ] | ${entry.ruleId} (${entry.lineInfoSet.size}) - ` +
|
|
87
|
+
`${entry.message}`
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
let count = 1
|
|
92
|
+
entry.lineInfoSet.forEach(lineInfo => {
|
|
93
|
+
console.log(`\t ${count}. ${lineInfo}`)
|
|
94
|
+
count++
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
if (entry?.issue) {
|
|
98
|
+
console.log(chalk.bold('Issue' + ': ') + entry.issue)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (entry?.advice) {
|
|
102
|
+
console.log(chalk.bold('Advice' + ': ') + entry.advice)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (entry?.learn && entry?.learn.length > 0) {
|
|
106
|
+
formatLinks('Learn', entry.learn)
|
|
107
|
+
}
|
|
108
|
+
console.log()
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
printVulnInfo(projectOverview)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function printVulnInfo(projectOverview: ProjectOverview) {
|
|
116
|
+
const totalVulnerabilities = getTotalVulns(projectOverview)
|
|
117
|
+
|
|
118
|
+
const vulMessage =
|
|
119
|
+
totalVulnerabilities === 1 ? `vulnerability` : `vulnerabilities`
|
|
120
|
+
console.log(chalk.bold(`Found ${totalVulnerabilities} ${vulMessage}`))
|
|
121
|
+
console.log(
|
|
122
|
+
i18n.__(
|
|
123
|
+
'foundDetailedVulnerabilities',
|
|
124
|
+
String(projectOverview.critical),
|
|
125
|
+
String(projectOverview.high),
|
|
126
|
+
String(projectOverview.medium),
|
|
127
|
+
String(projectOverview.low),
|
|
128
|
+
String(projectOverview.note)
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function getTotalVulns(projectOverview: ProjectOverview) {
|
|
134
|
+
return (
|
|
135
|
+
projectOverview.critical +
|
|
136
|
+
projectOverview.high +
|
|
137
|
+
projectOverview.medium +
|
|
138
|
+
projectOverview.low +
|
|
139
|
+
projectOverview.note
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function formatLinks(objName: string, entry: any[]) {
|
|
144
|
+
console.log(chalk.bold(objName + ':'))
|
|
145
|
+
entry.forEach(link => {
|
|
146
|
+
console.log(link)
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function getGroups(content: ResultContent[]) {
|
|
151
|
+
const groupTypeSet = new Set(content.map(({ ruleId }) => ruleId))
|
|
152
|
+
const groupTypeResults = [] as GroupedResultsModel[]
|
|
153
|
+
|
|
154
|
+
groupTypeSet.forEach(groupName => {
|
|
155
|
+
const groupResultsObj = new GroupedResultsModel(groupName)
|
|
156
|
+
|
|
157
|
+
content.forEach(resultEntry => {
|
|
158
|
+
if (resultEntry.ruleId === groupName) {
|
|
159
|
+
groupResultsObj.severity = resultEntry.severity
|
|
160
|
+
groupResultsObj.issue = stripMustacheTags(resultEntry.issue)
|
|
161
|
+
groupResultsObj.advice = resultEntry.advice
|
|
162
|
+
groupResultsObj.learn = resultEntry.learn
|
|
163
|
+
groupResultsObj.message = resultEntry.message?.text
|
|
164
|
+
|
|
165
|
+
groupResultsObj.lineInfoSet.add(getMessage(resultEntry.locations))
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
groupTypeResults.push(groupResultsObj)
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
return groupTypeResults
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function getMessage(locations: Location[]) {
|
|
175
|
+
const message = locations[0]?.physicalLocation?.artifactLocation?.uri || ''
|
|
176
|
+
const lineNumber = locations[0]?.physicalLocation?.region?.startLine || ''
|
|
177
|
+
|
|
178
|
+
if (!lineNumber) {
|
|
179
|
+
return '@' + message
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return '@' + message + ':' + lineNumber
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function stripMustacheTags(oldString: string) {
|
|
186
|
+
return oldString
|
|
187
|
+
.replace(/\n/g, ' ')
|
|
188
|
+
.replace(/{{.*?}}/g, '\n')
|
|
189
|
+
.replace(/\$\$LINK_DELIM\$\$/g, '\n')
|
|
190
|
+
.replace(/\s+/g, ' ')
|
|
191
|
+
.trim()
|
|
192
|
+
}
|
package/src/scan/scanConfig.js
CHANGED
|
@@ -26,7 +26,7 @@ const getScanConfig = argv => {
|
|
|
26
26
|
if (!Object.values(supportedLanguages).includes(scanParams.language)) {
|
|
27
27
|
console.log(`Did not recognise --language ${scanParams.language}`)
|
|
28
28
|
console.log(i18n.__('constantsHowToRunDev3'))
|
|
29
|
-
process.exit(
|
|
29
|
+
process.exit(1)
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -56,10 +56,12 @@ const startScan = async configToUse => {
|
|
|
56
56
|
getTimeout(configToUse),
|
|
57
57
|
startScanSpinner
|
|
58
58
|
)
|
|
59
|
+
|
|
59
60
|
const scanResultsInstances = await scanResults.returnScanResultsInstances(
|
|
60
61
|
configToUse,
|
|
61
62
|
scanDetail.id
|
|
62
63
|
)
|
|
64
|
+
|
|
63
65
|
const endTime = performance.now()
|
|
64
66
|
const scanDurationMs = endTime - startTime
|
|
65
67
|
succeedSpinner(startScanSpinner, 'Contrast Scan complete')
|
package/src/utils/getConfig.ts
CHANGED
|
@@ -7,6 +7,7 @@ type ContrastConfOptions = Partial<{
|
|
|
7
7
|
orgId: string
|
|
8
8
|
authHeader: string
|
|
9
9
|
numOfRuns: number
|
|
10
|
+
updateMessageHidden: boolean
|
|
10
11
|
}>
|
|
11
12
|
|
|
12
13
|
type ContrastConf = Conf<ContrastConfOptions>
|
|
@@ -17,6 +18,15 @@ const localConfig = (name: string, version: string) => {
|
|
|
17
18
|
})
|
|
18
19
|
config.set('version', version)
|
|
19
20
|
|
|
21
|
+
if (process.env.CONTRAST_CODSEC_DISABLE_UPDATE_MESSAGE) {
|
|
22
|
+
config.set(
|
|
23
|
+
'updateMessageHidden',
|
|
24
|
+
JSON.parse(
|
|
25
|
+
process.env.CONTRAST_CODSEC_DISABLE_UPDATE_MESSAGE.toLowerCase()
|
|
26
|
+
)
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
20
30
|
if (!config.has('host')) {
|
|
21
31
|
config.set('host', 'https://ce.contrastsecurity.com/')
|
|
22
32
|
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
const { getGlobalProperties, getFeatures, isFeatureEnabled } = require('../util/generalAPI');
|
|
3
|
-
const { CLI_IGNORE_DEV_DEPS } = require('../util/capabilities');
|
|
4
|
-
const checkDevDeps = async (config) => {
|
|
5
|
-
const shouldIgnoreDev = config.ignoreDev;
|
|
6
|
-
const globalProperties = await getGlobalProperties();
|
|
7
|
-
const features = getFeatures(globalProperties.internal_version);
|
|
8
|
-
const isfeatureEnabled = isFeatureEnabled(features, CLI_IGNORE_DEV_DEPS);
|
|
9
|
-
let ignoreDevUrl = false;
|
|
10
|
-
if (shouldIgnoreDev) {
|
|
11
|
-
ignoreDevUrl = isfeatureEnabled;
|
|
12
|
-
}
|
|
13
|
-
return ignoreDevUrl;
|
|
14
|
-
};
|
|
15
|
-
module.exports = {
|
|
16
|
-
checkDevDeps
|
|
17
|
-
};
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
const commonReport = require('./commonReportingFunctions');
|
|
3
|
-
const { handleResponseErrors } = require('../commonApi');
|
|
4
|
-
const { getHttpClient } = require('../../../utils/commonApi');
|
|
5
|
-
const vulnReportWithoutDevDep = async (analysis, applicationId, snapshotId, config) => {
|
|
6
|
-
if (config.report) {
|
|
7
|
-
const reportResponse = await getSpecReport(snapshotId, config);
|
|
8
|
-
if (reportResponse !== undefined) {
|
|
9
|
-
const severity = config.cveSeverity;
|
|
10
|
-
const id = applicationId;
|
|
11
|
-
const name = config.applicationName;
|
|
12
|
-
const hasSomeVulnerabilitiesReported = formatVulnerabilityOutput(reportResponse.vulnerabilities, severity, id, name, config);
|
|
13
|
-
commonReport.analyseReportOptions(hasSomeVulnerabilitiesReported);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
const getSpecReport = async (reportId, config) => {
|
|
18
|
-
const client = getHttpClient(config);
|
|
19
|
-
return client
|
|
20
|
-
.getSpecificReport(config, reportId)
|
|
21
|
-
.then(res => {
|
|
22
|
-
if (res.statusCode === 200) {
|
|
23
|
-
commonReport.displaySuccessMessageReport();
|
|
24
|
-
return res.body;
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
handleResponseErrors(res, 'report');
|
|
28
|
-
}
|
|
29
|
-
})
|
|
30
|
-
.catch(err => {
|
|
31
|
-
console.log(err);
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
const countSeverity = vulnerabilities => {
|
|
35
|
-
const severityCount = {
|
|
36
|
-
critical: 0,
|
|
37
|
-
high: 0,
|
|
38
|
-
medium: 0,
|
|
39
|
-
low: 0
|
|
40
|
-
};
|
|
41
|
-
for (const key of Object.keys(vulnerabilities)) {
|
|
42
|
-
vulnerabilities[key].forEach(vuln => {
|
|
43
|
-
if (vuln.severityCode === 'HIGH') {
|
|
44
|
-
severityCount['high'] += 1;
|
|
45
|
-
}
|
|
46
|
-
else if (vuln.severityCode === 'MEDIUM') {
|
|
47
|
-
severityCount['medium'] += 1;
|
|
48
|
-
}
|
|
49
|
-
else if (vuln.severityCode === 'LOW') {
|
|
50
|
-
severityCount['low'] += 1;
|
|
51
|
-
}
|
|
52
|
-
else if (vuln.severityCode === 'CRITICAL') {
|
|
53
|
-
severityCount['critical'] += 1;
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
return severityCount;
|
|
58
|
-
};
|
|
59
|
-
const formatVulnerabilityOutput = (vulnerabilities, severity, id, name, config) => {
|
|
60
|
-
const numberOfVulnerableLibraries = Object.keys(vulnerabilities).length;
|
|
61
|
-
let numberOfCves = 0;
|
|
62
|
-
for (const key of Object.keys(vulnerabilities)) {
|
|
63
|
-
numberOfCves += vulnerabilities[key].length;
|
|
64
|
-
}
|
|
65
|
-
commonReport.createLibraryHeader(id, numberOfVulnerableLibraries, numberOfCves, name);
|
|
66
|
-
const severityCount = countSeverity(vulnerabilities);
|
|
67
|
-
const filteredVulns = commonReport.filterVulnerabilitiesBySeverity(severity, vulnerabilities);
|
|
68
|
-
let hasSomeVulnerabilitiesReported;
|
|
69
|
-
hasSomeVulnerabilitiesReported = commonReport.printVulnerabilityResponse(severity, filteredVulns, vulnerabilities);
|
|
70
|
-
console.log('\n **************************' +
|
|
71
|
-
` Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVE's ` +
|
|
72
|
-
'************************** ');
|
|
73
|
-
console.log(' \n Please go to the Contrast UI to view your dependency tree: \n' +
|
|
74
|
-
` \n ${config.host}/Contrast/static/ng/index.html#/${config.organizationId}/applications/${config.applicationId}/libs/dependency-tree`);
|
|
75
|
-
return [hasSomeVulnerabilitiesReported, numberOfCves, severityCount];
|
|
76
|
-
};
|
|
77
|
-
module.exports = {
|
|
78
|
-
vulnReportWithoutDevDep: vulnReportWithoutDevDep,
|
|
79
|
-
formatVulnerabilityOutput: formatVulnerabilityOutput,
|
|
80
|
-
getSpecReport: getSpecReport
|
|
81
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
getGlobalProperties,
|
|
3
|
-
getFeatures,
|
|
4
|
-
isFeatureEnabled
|
|
5
|
-
} = require('../util/generalAPI')
|
|
6
|
-
const { CLI_IGNORE_DEV_DEPS } = require('../util/capabilities')
|
|
7
|
-
|
|
8
|
-
const checkDevDeps = async config => {
|
|
9
|
-
const shouldIgnoreDev = config.ignoreDev
|
|
10
|
-
const globalProperties = await getGlobalProperties()
|
|
11
|
-
|
|
12
|
-
// returns [ 'CLI_IGNORE_DEV_DEPS' ] if teamserver version is above 3.8.1
|
|
13
|
-
const features = getFeatures(globalProperties.internal_version)
|
|
14
|
-
|
|
15
|
-
// providing user is on version >= 3.8.1, isfeatureEnabled will always return true,
|
|
16
|
-
// therefore shouldIgnoreDev flag (from params) is needed to disable ignore dev deps
|
|
17
|
-
const isfeatureEnabled = isFeatureEnabled(features, CLI_IGNORE_DEV_DEPS)
|
|
18
|
-
let ignoreDevUrl = false
|
|
19
|
-
if (shouldIgnoreDev) {
|
|
20
|
-
ignoreDevUrl = isfeatureEnabled
|
|
21
|
-
}
|
|
22
|
-
return ignoreDevUrl
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
module.exports = {
|
|
26
|
-
checkDevDeps
|
|
27
|
-
}
|