@contrast/contrast 1.0.7 → 1.0.8
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/autodetection/autoDetectLanguage.js +3 -3
- package/dist/audit/catalogueApplication/catalogueApplication.js +23 -5
- package/dist/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +5 -5
- package/dist/audit/languageAnalysisEngine/getProjectRootFilenames.js +9 -9
- package/dist/audit/languageAnalysisEngine/index.js +2 -2
- package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +5 -28
- package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +11 -4
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +39 -13
- package/dist/audit/languageAnalysisEngine/report/models/reportListModel.js +2 -1
- package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +3 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +35 -14
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +3 -3
- package/dist/audit/save.js +29 -0
- package/dist/commands/audit/auditController.js +21 -5
- package/dist/commands/audit/help.js +24 -1
- package/dist/commands/audit/processAudit.js +7 -1
- package/dist/commands/audit/saveFile.js +7 -3
- package/dist/commands/scan/sca/scaAnalysis.js +31 -10
- package/dist/common/HTTPClient.js +6 -0
- package/dist/common/versionChecker.js +19 -4
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +12 -11
- package/dist/constants.js +9 -4
- package/dist/index.js +4 -3
- package/dist/sbom/generateSbom.js +4 -3
- package/dist/scaAnalysis/common/formatMessage.js +26 -5
- package/dist/scaAnalysis/common/treeUpload.js +0 -1
- package/dist/scaAnalysis/go/goReadDepFile.js +1 -3
- package/dist/scaAnalysis/java/analysis.js +5 -5
- package/dist/scaAnalysis/javascript/analysis.js +110 -0
- package/dist/scaAnalysis/javascript/index.js +41 -0
- package/dist/scaAnalysis/php/analysis.js +89 -0
- package/dist/scaAnalysis/php/index.js +10 -0
- package/dist/scaAnalysis/python/analysis.js +8 -7
- package/dist/scaAnalysis/ruby/analysis.js +8 -8
- package/dist/scaAnalysis/ruby/index.js +2 -2
- package/dist/scan/autoDetection.js +4 -4
- package/dist/scan/fileUtils.js +13 -2
- package/dist/utils/filterProjectPath.js +7 -2
- package/package.json +3 -3
- package/src/audit/autodetection/autoDetectLanguage.ts +3 -3
- package/src/audit/catalogueApplication/catalogueApplication.js +28 -6
- package/src/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +5 -5
- package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +11 -11
- package/src/audit/languageAnalysisEngine/index.js +2 -2
- package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +4 -32
- package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +20 -19
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +67 -17
- package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +4 -1
- package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +4 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +49 -17
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +1 -1
- package/src/audit/save.js +32 -0
- package/src/commands/audit/auditController.ts +22 -13
- package/src/commands/audit/help.ts +24 -1
- package/src/commands/audit/processAudit.ts +6 -3
- package/src/commands/audit/saveFile.ts +5 -1
- package/src/commands/scan/sca/scaAnalysis.js +53 -22
- package/src/common/HTTPClient.js +7 -0
- package/src/common/versionChecker.ts +23 -4
- package/src/constants/constants.js +1 -1
- package/src/constants/locales.js +12 -11
- package/src/constants.js +9 -4
- package/src/index.ts +5 -3
- package/src/sbom/generateSbom.ts +1 -1
- package/src/scaAnalysis/common/formatMessage.js +27 -5
- package/src/scaAnalysis/common/treeUpload.js +0 -1
- package/src/scaAnalysis/go/goReadDepFile.js +1 -3
- package/src/scaAnalysis/java/analysis.js +5 -5
- package/src/scaAnalysis/javascript/analysis.js +127 -0
- package/src/scaAnalysis/javascript/index.js +56 -0
- package/src/scaAnalysis/php/analysis.js +98 -0
- package/src/scaAnalysis/php/index.js +11 -0
- package/src/scaAnalysis/python/analysis.js +8 -7
- package/src/scaAnalysis/ruby/analysis.js +8 -8
- package/src/scaAnalysis/ruby/index.js +2 -2
- package/src/scan/autoDetection.js +4 -4
- package/src/scan/fileUtils.js +13 -2
- package/src/utils/filterProjectPath.js +6 -2
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
findCVESeveritiesAndOrderByHighestPriority,
|
|
13
13
|
findHighestSeverityCVE,
|
|
14
14
|
findNameAndVersion,
|
|
15
|
-
severityCountAllCVEs
|
|
15
|
+
severityCountAllCVEs,
|
|
16
|
+
severityCountAllLibraries
|
|
16
17
|
} from './utils/reportUtils'
|
|
17
18
|
import { SeverityCountModel } from './models/severityCountModel'
|
|
18
19
|
import {
|
|
@@ -20,6 +21,13 @@ import {
|
|
|
20
21
|
ReportOutputHeaderModel,
|
|
21
22
|
ReportOutputModel
|
|
22
23
|
} from './models/reportOutputModel'
|
|
24
|
+
import {
|
|
25
|
+
CRITICAL_COLOUR,
|
|
26
|
+
HIGH_COLOUR,
|
|
27
|
+
LOW_COLOUR,
|
|
28
|
+
MEDIUM_COLOUR,
|
|
29
|
+
NOTE_COLOUR
|
|
30
|
+
} from '../../../constants/constants'
|
|
23
31
|
|
|
24
32
|
export const createLibraryHeader = (
|
|
25
33
|
id: string,
|
|
@@ -27,11 +35,9 @@ export const createLibraryHeader = (
|
|
|
27
35
|
numberOfCves: number
|
|
28
36
|
) => {
|
|
29
37
|
numberOfVulnerableLibraries === 1
|
|
30
|
-
? console.log(
|
|
31
|
-
` Found 1 vulnerable library containing ${numberOfCves} CVE's`
|
|
32
|
-
)
|
|
38
|
+
? console.log(`Found 1 vulnerable library containing ${numberOfCves} CVEs`)
|
|
33
39
|
: console.log(
|
|
34
|
-
`
|
|
40
|
+
`Found ${numberOfVulnerableLibraries} vulnerable libraries containing ${numberOfCves} CVEs `
|
|
35
41
|
)
|
|
36
42
|
}
|
|
37
43
|
|
|
@@ -43,10 +49,6 @@ export const getReport = async (config: any, reportId: string) => {
|
|
|
43
49
|
if (res.statusCode === 200) {
|
|
44
50
|
return res.body
|
|
45
51
|
} else {
|
|
46
|
-
console.log('config-------------------')
|
|
47
|
-
console.log(config)
|
|
48
|
-
console.log('reportId----------------')
|
|
49
|
-
console.log(reportId)
|
|
50
52
|
console.log(JSON.stringify(res))
|
|
51
53
|
handleResponseErrors(res, 'report')
|
|
52
54
|
}
|
|
@@ -81,7 +83,11 @@ export const printFormattedOutput = (
|
|
|
81
83
|
new ReportCompositeKey(
|
|
82
84
|
name,
|
|
83
85
|
version,
|
|
84
|
-
findHighestSeverityCVE(library.cveArray) as ReportSeverityModel
|
|
86
|
+
findHighestSeverityCVE(library.cveArray) as ReportSeverityModel,
|
|
87
|
+
severityCountAllCVEs(
|
|
88
|
+
library.cveArray,
|
|
89
|
+
new SeverityCountModel()
|
|
90
|
+
).getTotal
|
|
85
91
|
),
|
|
86
92
|
library.cveArray
|
|
87
93
|
)
|
|
@@ -89,15 +95,23 @@ export const printFormattedOutput = (
|
|
|
89
95
|
report.reportOutputList.push(newOutputModel)
|
|
90
96
|
}
|
|
91
97
|
|
|
92
|
-
const
|
|
98
|
+
const outputOrderedByLowestSeverityAndLowestNumOfCvesFirst = orderBy(
|
|
93
99
|
report.reportOutputList,
|
|
94
|
-
|
|
100
|
+
[
|
|
101
|
+
(reportListItem: ReportModelStructure) => {
|
|
102
|
+
return reportListItem.compositeKey.highestSeverity.priority
|
|
103
|
+
},
|
|
104
|
+
(reportListItem: ReportModelStructure) => {
|
|
105
|
+
return reportListItem.compositeKey.numberOfSeverities
|
|
106
|
+
}
|
|
107
|
+
],
|
|
95
108
|
['desc']
|
|
96
109
|
)
|
|
97
110
|
|
|
98
|
-
let contrastHeaderNumCounter =
|
|
99
|
-
|
|
100
|
-
|
|
111
|
+
let contrastHeaderNumCounter =
|
|
112
|
+
outputOrderedByLowestSeverityAndLowestNumOfCvesFirst.length + 1
|
|
113
|
+
for (const reportModel of outputOrderedByLowestSeverityAndLowestNumOfCvesFirst) {
|
|
114
|
+
contrastHeaderNumCounter--
|
|
101
115
|
const { libraryName, libraryVersion, highestSeverity } =
|
|
102
116
|
reportModel.compositeKey
|
|
103
117
|
const numOfCVEs = reportModel.cveArray.length
|
|
@@ -118,7 +132,22 @@ export const printFormattedOutput = (
|
|
|
118
132
|
reportOutputModel.header.introducesMessage
|
|
119
133
|
)
|
|
120
134
|
console.log(reportOutputModel.body.issueMessage)
|
|
121
|
-
console.log(reportOutputModel.body.adviceMessage)
|
|
135
|
+
console.log(reportOutputModel.body.adviceMessage + '\n')
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const {
|
|
139
|
+
criticalMessage,
|
|
140
|
+
highMessage,
|
|
141
|
+
mediumMessage,
|
|
142
|
+
lowMessage,
|
|
143
|
+
noteMessage,
|
|
144
|
+
total
|
|
145
|
+
} = buildFooter(libraries)
|
|
146
|
+
|
|
147
|
+
if (total > 1) {
|
|
148
|
+
console.log(
|
|
149
|
+
`${criticalMessage} | ${highMessage} | ${mediumMessage} | ${lowMessage} | ${noteMessage}`
|
|
150
|
+
)
|
|
122
151
|
}
|
|
123
152
|
}
|
|
124
153
|
|
|
@@ -130,7 +159,7 @@ export function buildHeader(
|
|
|
130
159
|
numOfCVEs: number
|
|
131
160
|
) {
|
|
132
161
|
const vulnerabilityPluralised =
|
|
133
|
-
numOfCVEs > 1 ? '
|
|
162
|
+
numOfCVEs > 1 ? 'vulnerabilities' : 'vulnerability'
|
|
134
163
|
const formattedHeaderNum = buildFormattedHeaderNum(contrastHeaderNum)
|
|
135
164
|
|
|
136
165
|
const vulnMessage = chalk
|
|
@@ -176,6 +205,27 @@ export function buildBody(cveArray: ReportCVEModel[]) {
|
|
|
176
205
|
return new ReportOutputBodyModel(issueMessage, adviceMessage)
|
|
177
206
|
}
|
|
178
207
|
|
|
208
|
+
const buildFooter = (libraries: ReportLibraryModel[]) => {
|
|
209
|
+
const { critical, high, medium, low, note, getTotal } =
|
|
210
|
+
severityCountAllLibraries(libraries)
|
|
211
|
+
const criticalMessage = chalk
|
|
212
|
+
.hex(CRITICAL_COLOUR)
|
|
213
|
+
.bold(`${critical} Critical`)
|
|
214
|
+
const highMessage = chalk.hex(HIGH_COLOUR).bold(`${high} High`)
|
|
215
|
+
const mediumMessage = chalk.hex(MEDIUM_COLOUR).bold(`${medium} Medium`)
|
|
216
|
+
const lowMessage = chalk.hex(LOW_COLOUR).bold(`${low} Low`)
|
|
217
|
+
const noteMessage = chalk.hex(NOTE_COLOUR).bold(`${note} Note`)
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
criticalMessage,
|
|
221
|
+
highMessage,
|
|
222
|
+
mediumMessage,
|
|
223
|
+
lowMessage,
|
|
224
|
+
noteMessage,
|
|
225
|
+
total: getTotal
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
179
229
|
export function buildFormattedHeaderNum(contrastHeaderNum: number) {
|
|
180
230
|
let formattedHeaderNum
|
|
181
231
|
|
|
@@ -23,14 +23,17 @@ export class ReportCompositeKey {
|
|
|
23
23
|
libraryName!: string
|
|
24
24
|
libraryVersion!: string
|
|
25
25
|
highestSeverity!: ReportSeverityModel
|
|
26
|
+
numberOfSeverities!: number
|
|
26
27
|
|
|
27
28
|
constructor(
|
|
28
29
|
libraryName: string,
|
|
29
30
|
libraryVersion: string,
|
|
30
|
-
highestSeverity: ReportSeverityModel
|
|
31
|
+
highestSeverity: ReportSeverityModel,
|
|
32
|
+
numberOfSeverities: number
|
|
31
33
|
) {
|
|
32
34
|
this.libraryName = libraryName
|
|
33
35
|
this.libraryVersion = libraryVersion
|
|
34
36
|
this.highestSeverity = highestSeverity
|
|
37
|
+
this.numberOfSeverities = numberOfSeverities
|
|
35
38
|
}
|
|
36
39
|
}
|
|
@@ -4,9 +4,11 @@ import {
|
|
|
4
4
|
printVulnerabilityResponse
|
|
5
5
|
} from './commonReportingFunctions'
|
|
6
6
|
import {
|
|
7
|
-
|
|
7
|
+
convertGenericToTypedLibraryVulns,
|
|
8
8
|
severityCountAllLibraries
|
|
9
9
|
} from './utils/reportUtils'
|
|
10
|
+
import i18n from 'i18n'
|
|
11
|
+
import chalk from 'chalk'
|
|
10
12
|
|
|
11
13
|
export async function vulnerabilityReport(
|
|
12
14
|
analysis: any,
|
|
@@ -17,11 +19,9 @@ export async function vulnerabilityReport(
|
|
|
17
19
|
|
|
18
20
|
if (reportResponse !== undefined) {
|
|
19
21
|
const id = applicationId
|
|
20
|
-
const name = analysis.config.applicationName
|
|
21
22
|
formatVulnerabilityOutput(
|
|
22
23
|
reportResponse.vulnerabilities,
|
|
23
24
|
id,
|
|
24
|
-
name,
|
|
25
25
|
analysis.config
|
|
26
26
|
)
|
|
27
27
|
}
|
|
@@ -30,27 +30,59 @@ export async function vulnerabilityReport(
|
|
|
30
30
|
export function formatVulnerabilityOutput(
|
|
31
31
|
libraryVulnerabilityResponse: any,
|
|
32
32
|
id: string,
|
|
33
|
-
name: string,
|
|
34
33
|
config: any
|
|
35
34
|
) {
|
|
36
|
-
const vulnerableLibraries =
|
|
35
|
+
const vulnerableLibraries = convertGenericToTypedLibraryVulns(
|
|
37
36
|
libraryVulnerabilityResponse
|
|
38
37
|
)
|
|
39
38
|
|
|
40
39
|
const numberOfVulnerableLibraries = vulnerableLibraries.length
|
|
41
|
-
let numberOfCves = 0
|
|
42
|
-
vulnerableLibraries.forEach(lib => (numberOfCves += lib.cveArray.length))
|
|
43
40
|
|
|
44
|
-
|
|
41
|
+
if (numberOfVulnerableLibraries === 0) {
|
|
42
|
+
console.log(i18n.__('scanNoVulnerabilitiesFound'))
|
|
43
|
+
console.log(i18n.__('scanNoVulnerabilitiesFoundSecureCode'))
|
|
44
|
+
console.log(i18n.__('scanNoVulnerabilitiesFoundGoodWork'))
|
|
45
|
+
console.log(
|
|
46
|
+
chalk.bold(`Found ${numberOfVulnerableLibraries} vulnerabilities`)
|
|
47
|
+
)
|
|
48
|
+
console.log(
|
|
49
|
+
i18n.__(
|
|
50
|
+
'foundDetailedVulnerabilities',
|
|
51
|
+
String(0),
|
|
52
|
+
String(0),
|
|
53
|
+
String(0),
|
|
54
|
+
String(0),
|
|
55
|
+
String(0)
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
} else {
|
|
59
|
+
let numberOfCves = 0
|
|
60
|
+
vulnerableLibraries.forEach(lib => (numberOfCves += lib.cveArray.length))
|
|
45
61
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
62
|
+
createLibraryHeader(id, numberOfVulnerableLibraries, numberOfCves)
|
|
63
|
+
|
|
64
|
+
const hasSomeVulnerabilitiesReported = printVulnerabilityResponse(
|
|
65
|
+
vulnerableLibraries,
|
|
66
|
+
config
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
return [
|
|
70
|
+
hasSomeVulnerabilitiesReported,
|
|
71
|
+
numberOfCves,
|
|
72
|
+
severityCountAllLibraries(vulnerableLibraries)
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function vulnerabilityReportV2(config: any, reportId: string) {
|
|
78
|
+
const reportResponse = await getReport(config, reportId)
|
|
50
79
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
80
|
+
if (reportResponse !== undefined) {
|
|
81
|
+
const name = config.applicationName
|
|
82
|
+
formatVulnerabilityOutput(
|
|
83
|
+
reportResponse.vulnerabilities,
|
|
84
|
+
config.applicationId,
|
|
85
|
+
config
|
|
86
|
+
)
|
|
87
|
+
}
|
|
56
88
|
}
|
|
@@ -67,7 +67,7 @@ export function findCVESeverity(cve: ReportCVEModel) {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
export function
|
|
70
|
+
export function convertGenericToTypedLibraryVulns(libraries: any) {
|
|
71
71
|
return Object.entries(libraries).map(([name, cveArray]) => {
|
|
72
72
|
return new ReportLibraryModel(name, cveArray as ReportCVEModel[])
|
|
73
73
|
})
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const i18n = require('i18n')
|
|
3
|
+
const chalk = require('chalk')
|
|
4
|
+
const save = require('../commands/audit/saveFile')
|
|
5
|
+
const sbom = require('../sbom/generateSbom')
|
|
6
|
+
|
|
7
|
+
async function auditSave(config) {
|
|
8
|
+
if (config.save) {
|
|
9
|
+
if (config.save.toLowerCase() === 'sbom') {
|
|
10
|
+
save.saveFile(config, await sbom.generateSbom(config))
|
|
11
|
+
|
|
12
|
+
const filename = `${config.applicationId}-sbom-cyclonedx.json`
|
|
13
|
+
if (fs.existsSync(filename)) {
|
|
14
|
+
console.log(i18n.__('auditSBOMSaveSuccess') + ` - ${filename}`)
|
|
15
|
+
} else {
|
|
16
|
+
console.log(
|
|
17
|
+
chalk.yellow.bold(
|
|
18
|
+
`\n Unable to save ${filename} Software Bill of Materials (SBOM)`
|
|
19
|
+
)
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
} else {
|
|
23
|
+
console.log(i18n.__('auditBadFiletypeSpecifiedForSave'))
|
|
24
|
+
}
|
|
25
|
+
} else if (config.save === null) {
|
|
26
|
+
console.log(i18n.__('auditNoFiletypeSpecifiedForSave'))
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
auditSave
|
|
32
|
+
}
|
|
@@ -3,7 +3,6 @@ import commonApi from '../../audit/languageAnalysisEngine/commonApi'
|
|
|
3
3
|
|
|
4
4
|
const identifyLanguageAE = require('./../../audit/languageAnalysisEngine')
|
|
5
5
|
const languageFactory = require('../../audit/languageAnalysisEngine/languageAnalysisFactory')
|
|
6
|
-
const { v4: uuidv4 } = require('uuid')
|
|
7
6
|
|
|
8
7
|
export const dealWithNoAppId = async (config: { [x: string]: string }) => {
|
|
9
8
|
let appID: string
|
|
@@ -14,14 +13,15 @@ export const dealWithNoAppId = async (config: { [x: string]: string }) => {
|
|
|
14
13
|
return await catalogueApplication(config)
|
|
15
14
|
}
|
|
16
15
|
if (!appID && !config.applicationName) {
|
|
17
|
-
config.applicationName =
|
|
18
|
-
|
|
16
|
+
config.applicationName = getAppName(config.file) as string
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
appID = await commonApi.returnAppId(config)
|
|
19
|
+
if (!appID) {
|
|
20
|
+
return await catalogueApplication(config)
|
|
21
|
+
}
|
|
19
22
|
}
|
|
20
|
-
|
|
21
|
-
} catch (e) {
|
|
22
|
-
// @ts-ignore
|
|
23
|
+
} catch (e: any) {
|
|
23
24
|
if (e.toString().includes('tunneling socket could not be established')) {
|
|
24
|
-
// @ts-ignore
|
|
25
25
|
console.log(e.message.toString())
|
|
26
26
|
console.log(
|
|
27
27
|
'There seems to be an issue with your proxy, please check and try again'
|
|
@@ -37,10 +37,19 @@ export const startAudit = async (config: { [key: string]: string }) => {
|
|
|
37
37
|
// @ts-ignore
|
|
38
38
|
config.applicationId = await dealWithNoAppId(config)
|
|
39
39
|
}
|
|
40
|
-
identifyLanguageAE(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
)
|
|
40
|
+
identifyLanguageAE(config.file, languageFactory, config.applicationId, config)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const getAppName = (file: string) => {
|
|
44
|
+
const last = file.charAt(file.length - 1)
|
|
45
|
+
if (last !== '/') {
|
|
46
|
+
return file.split('/').pop()
|
|
47
|
+
} else {
|
|
48
|
+
const str = removeLastChar(file)
|
|
49
|
+
return str.split('/').pop()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const removeLastChar = (str: string) => {
|
|
54
|
+
return str.substring(0, str.length - 1)
|
|
46
55
|
}
|
|
@@ -41,7 +41,30 @@ const auditUsageGuide = commandLineUsage([
|
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
header: i18n.__('constantsAuditOptions'),
|
|
44
|
-
optionList: constants.commandLineDefinitions.auditOptionDefinitions
|
|
44
|
+
optionList: constants.commandLineDefinitions.auditOptionDefinitions,
|
|
45
|
+
hide: [
|
|
46
|
+
'application-id',
|
|
47
|
+
'application-name',
|
|
48
|
+
'organization-id',
|
|
49
|
+
'api-key',
|
|
50
|
+
'authorization',
|
|
51
|
+
'host',
|
|
52
|
+
'proxy',
|
|
53
|
+
'help',
|
|
54
|
+
'ff',
|
|
55
|
+
'ignore-cert-errors',
|
|
56
|
+
'verbose',
|
|
57
|
+
'debug',
|
|
58
|
+
'experimental',
|
|
59
|
+
'tags',
|
|
60
|
+
'sub-project',
|
|
61
|
+
'code',
|
|
62
|
+
'maven-settings-path',
|
|
63
|
+
'language',
|
|
64
|
+
'experimental',
|
|
65
|
+
'app-groups',
|
|
66
|
+
'metadata'
|
|
67
|
+
]
|
|
45
68
|
}
|
|
46
69
|
])
|
|
47
70
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { startAudit } from './auditController'
|
|
2
2
|
import { getAuditConfig } from './auditConfig'
|
|
3
3
|
import { auditUsageGuide } from './help'
|
|
4
|
+
import { processSca } from '../scan/sca/scaAnalysis'
|
|
4
5
|
|
|
5
6
|
export type parameterInput = string[]
|
|
6
7
|
|
|
@@ -11,9 +12,11 @@ export const processAudit = async (argv: parameterInput) => {
|
|
|
11
12
|
}
|
|
12
13
|
const config = getAuditConfig(argv)
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
if (config.experimental) {
|
|
16
|
+
await processSca(config)
|
|
17
|
+
} else {
|
|
18
|
+
await startAudit(config)
|
|
19
|
+
}
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
const printHelpMessage = () => {
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import fs from 'fs'
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export const saveFile = (config: any, rawResults: any) => {
|
|
4
4
|
const fileName = `${config.applicationId}-sbom-cyclonedx.json`
|
|
5
5
|
fs.writeFileSync(fileName, JSON.stringify(rawResults))
|
|
6
6
|
}
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
saveFile
|
|
10
|
+
}
|
|
@@ -6,19 +6,35 @@ const {
|
|
|
6
6
|
} = require('../../../scan/autoDetection')
|
|
7
7
|
const auditController = require('../../audit/auditController')
|
|
8
8
|
const {
|
|
9
|
-
supportedLanguages: { JAVA, GO, RUBY,
|
|
9
|
+
supportedLanguages: { JAVA, GO, PYTHON, RUBY, JAVASCRIPT, NODE, PHP }
|
|
10
10
|
} = require('../../../audit/languageAnalysisEngine/constants')
|
|
11
11
|
const goAnalysis = require('../../../scaAnalysis/go/goAnalysis')
|
|
12
|
+
const phpAnalysis = require('../../../scaAnalysis/php/index')
|
|
12
13
|
const { rubyAnalysis } = require('../../../scaAnalysis/ruby')
|
|
13
14
|
const { pythonAnalysis } = require('../../../scaAnalysis/python')
|
|
15
|
+
const javascriptAnalysis = require('../../../scaAnalysis/javascript')
|
|
16
|
+
const {
|
|
17
|
+
pollForSnapshotCompletition
|
|
18
|
+
} = require('../../../audit/languageAnalysisEngine/sendSnapshot')
|
|
19
|
+
const {
|
|
20
|
+
returnOra,
|
|
21
|
+
startSpinner,
|
|
22
|
+
succeedSpinner
|
|
23
|
+
} = require('../../../utils/oraWrapper')
|
|
24
|
+
const i18n = require('i18n')
|
|
25
|
+
const {
|
|
26
|
+
vulnerabilityReportV2
|
|
27
|
+
} = require('../../../audit/languageAnalysisEngine/report/reportingFeature')
|
|
28
|
+
const auditSave = require('../../../audit/save')
|
|
14
29
|
|
|
15
30
|
const processSca = async config => {
|
|
16
31
|
let filesFound
|
|
17
|
-
if (config.
|
|
18
|
-
|
|
32
|
+
if (config.file) {
|
|
33
|
+
config.file = config.file.concat('/')
|
|
34
|
+
filesFound = await manualDetectAuditFilesAndLanguages(config.file)
|
|
19
35
|
} else {
|
|
20
36
|
filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config)
|
|
21
|
-
config.
|
|
37
|
+
config.file = process.cwd().concat('/')
|
|
22
38
|
}
|
|
23
39
|
|
|
24
40
|
// files found looks like [ { javascript: [ Array ] } ]
|
|
@@ -31,26 +47,25 @@ const processSca = async config => {
|
|
|
31
47
|
messageToSend = javaAnalysis.javaAnalysis(config, filesFound[0])
|
|
32
48
|
config.language = JAVA
|
|
33
49
|
break
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
case RUBY:
|
|
41
|
-
messageToSend = rubyAnalysis(config, filesFound[0])
|
|
42
|
-
config.language = RUBY
|
|
50
|
+
case JAVASCRIPT:
|
|
51
|
+
messageToSend = await javascriptAnalysis.jsAnalysis(
|
|
52
|
+
config,
|
|
53
|
+
filesFound[0]
|
|
54
|
+
)
|
|
55
|
+
config.language = NODE
|
|
43
56
|
break
|
|
44
57
|
case PYTHON:
|
|
45
58
|
messageToSend = pythonAnalysis(config, filesFound[0])
|
|
46
59
|
config.language = PYTHON
|
|
47
60
|
break
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
61
|
+
case RUBY:
|
|
62
|
+
messageToSend = rubyAnalysis(config, filesFound[0])
|
|
63
|
+
config.language = RUBY
|
|
64
|
+
break
|
|
65
|
+
case 'PHP':
|
|
66
|
+
messageToSend = phpAnalysis.phpAnalysis(config, filesFound[0])
|
|
67
|
+
config.language = PHP
|
|
68
|
+
break
|
|
54
69
|
case GO:
|
|
55
70
|
messageToSend = goAnalysis.goAnalysis(config, filesFound[0])
|
|
56
71
|
config.language = GO
|
|
@@ -65,14 +80,30 @@ const processSca = async config => {
|
|
|
65
80
|
config.applicationId = await auditController.dealWithNoAppId(config)
|
|
66
81
|
}
|
|
67
82
|
//send message to TS
|
|
68
|
-
|
|
69
|
-
|
|
83
|
+
const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'))
|
|
84
|
+
startSpinner(reportSpinner)
|
|
85
|
+
const snapshotResponse = await treeUpload.commonSendSnapShot(
|
|
86
|
+
messageToSend,
|
|
87
|
+
config
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
//poll for completion
|
|
91
|
+
await pollForSnapshotCompletition(
|
|
92
|
+
config,
|
|
93
|
+
snapshotResponse.id,
|
|
94
|
+
reportSpinner
|
|
95
|
+
)
|
|
96
|
+
succeedSpinner(reportSpinner, 'Contrast SCA audit complete')
|
|
97
|
+
|
|
98
|
+
await vulnerabilityReportV2(config, snapshotResponse.id)
|
|
99
|
+
|
|
100
|
+
await auditSave.auditSave(config)
|
|
70
101
|
} else {
|
|
71
102
|
if (filesFound.length === 0) {
|
|
72
103
|
console.log('no compatible dependency files detected. Continuing...')
|
|
73
104
|
} else {
|
|
74
105
|
console.log(
|
|
75
|
-
'multiple language files detected, please use --
|
|
106
|
+
'multiple language files detected, please use --file to specify a directory or the file where dependencies are declared'
|
|
76
107
|
)
|
|
77
108
|
}
|
|
78
109
|
}
|
package/src/common/HTTPClient.js
CHANGED
|
@@ -339,6 +339,13 @@ HTTPClient.prototype.getSbom = function getSbom(config) {
|
|
|
339
339
|
return requestUtils.sendRequest({ method: 'get', options })
|
|
340
340
|
}
|
|
341
341
|
|
|
342
|
+
HTTPClient.prototype.getLatestVersion = function getLatestVersion() {
|
|
343
|
+
const options = _.cloneDeep(this.requestOptions)
|
|
344
|
+
options.url =
|
|
345
|
+
'https://pkg.contrastsecurity.com/artifactory/cli/latest-version.txt'
|
|
346
|
+
return requestUtils.sendRequest({ method: 'get', options })
|
|
347
|
+
}
|
|
348
|
+
|
|
342
349
|
// analytics
|
|
343
350
|
|
|
344
351
|
HTTPClient.prototype.postAnalyticsFunction = function (config, provider, body) {
|
|
@@ -1,12 +1,31 @@
|
|
|
1
|
-
import latestVersion from 'latest-version'
|
|
2
1
|
import { APP_VERSION } from '../constants/constants'
|
|
3
2
|
import boxen from 'boxen'
|
|
4
3
|
import chalk from 'chalk'
|
|
5
4
|
import semver from 'semver'
|
|
5
|
+
import commonApi from '../utils/commonApi'
|
|
6
|
+
import { constants } from 'http2'
|
|
7
|
+
import { ContrastConf } from '../utils/getConfig'
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const getLatestVersion = async (config: any) => {
|
|
10
|
+
const client = commonApi.getHttpClient(config)
|
|
11
|
+
try {
|
|
12
|
+
const res = await client.getLatestVersion()
|
|
13
|
+
if (res.statusCode === constants.HTTP_STATUS_OK) {
|
|
14
|
+
return res.body
|
|
15
|
+
}
|
|
16
|
+
} catch (e) {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
export async function findLatestCLIVersion(config: ContrastConf) {
|
|
23
|
+
const messageHidden = config.get('updateMessageHidden') as boolean
|
|
24
|
+
|
|
25
|
+
if (!messageHidden) {
|
|
26
|
+
let latestCLIVersion: string = await getLatestVersion(config)
|
|
27
|
+
//strip key
|
|
28
|
+
latestCLIVersion = latestCLIVersion.substring(8)
|
|
10
29
|
|
|
11
30
|
if (semver.lt(APP_VERSION, latestCLIVersion)) {
|
|
12
31
|
const updateAvailableMessage = `Update available ${chalk.yellow(
|
|
@@ -13,7 +13,7 @@ const MEDIUM = 'MEDIUM'
|
|
|
13
13
|
const HIGH = 'HIGH'
|
|
14
14
|
const CRITICAL = 'CRITICAL'
|
|
15
15
|
const APP_NAME = 'contrast'
|
|
16
|
-
const APP_VERSION = '1.0.
|
|
16
|
+
const APP_VERSION = '1.0.8'
|
|
17
17
|
const TIMEOUT = 120000
|
|
18
18
|
const HIGH_COLOUR = '#ff9900'
|
|
19
19
|
const CRITICAL_COLOUR = '#e35858'
|