@contrast/contrast 1.0.5 → 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/.prettierignore +0 -5
- package/dist/audit/autodetection/autoDetectLanguage.js +3 -3
- package/dist/audit/catalogueApplication/catalogueApplication.js +23 -5
- package/dist/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +4 -2
- package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
- package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
- package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
- 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 +6 -27
- package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +25 -5
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +99 -20
- package/dist/audit/languageAnalysisEngine/report/models/reportListModel.js +2 -1
- package/dist/audit/languageAnalysisEngine/report/models/reportOutputModel.js +24 -0
- package/dist/audit/languageAnalysisEngine/report/models/reportSeverityModel.js +3 -1
- package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +16 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +35 -14
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +58 -47
- package/dist/audit/languageAnalysisEngine/sendSnapshot.js +65 -3
- package/dist/audit/save.js +29 -0
- package/dist/commands/audit/auditController.js +22 -6
- package/dist/commands/audit/help.js +24 -1
- package/dist/commands/audit/processAudit.js +8 -2
- package/dist/commands/audit/saveFile.js +7 -3
- package/dist/commands/scan/processScan.js +1 -1
- package/dist/commands/scan/sca/scaAnalysis.js +48 -11
- package/dist/common/HTTPClient.js +56 -15
- package/dist/common/errorHandling.js +6 -1
- package/dist/common/versionChecker.js +20 -5
- package/dist/constants/constants.js +13 -3
- package/dist/constants/locales.js +15 -12
- package/dist/constants.js +9 -4
- package/dist/index.js +4 -3
- package/dist/lambda/analytics.js +11 -0
- package/dist/lambda/lambda.js +35 -4
- package/dist/lambda/types.js +13 -0
- package/dist/sbom/generateSbom.js +4 -3
- package/dist/scaAnalysis/common/formatMessage.js +46 -1
- package/dist/scaAnalysis/common/treeUpload.js +1 -3
- package/dist/scaAnalysis/go/goAnalysis.js +17 -0
- package/dist/scaAnalysis/go/goParseDeps.js +158 -0
- package/dist/scaAnalysis/go/goReadDepFile.js +21 -0
- package/dist/scaAnalysis/java/analysis.js +11 -22
- package/dist/scaAnalysis/java/index.js +6 -6
- package/dist/scaAnalysis/java/javaBuildDepsParser.js +14 -1
- 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 +42 -0
- package/dist/scaAnalysis/python/index.js +10 -0
- package/dist/scaAnalysis/ruby/analysis.js +226 -0
- package/dist/scaAnalysis/ruby/index.js +10 -0
- package/dist/scan/autoDetection.js +8 -4
- package/dist/scan/fileUtils.js +26 -8
- package/dist/scan/formatScanOutput.js +18 -17
- package/dist/scan/models/groupedResultsModel.js +1 -1
- package/dist/scan/models/scanResultsModel.js +3 -1
- package/dist/scan/populateProjectIdAndProjectName.js +2 -1
- package/dist/scan/scan.js +5 -3
- package/dist/scan/scanConfig.js +6 -1
- package/dist/scan/scanController.js +26 -6
- package/dist/scan/scanResults.js +20 -6
- package/dist/utils/commonApi.js +4 -1
- package/dist/utils/filterProjectPath.js +7 -2
- package/dist/utils/oraWrapper.js +5 -1
- package/package.json +13 -9
- package/src/audit/autodetection/autoDetectLanguage.ts +3 -3
- package/src/audit/catalogueApplication/catalogueApplication.js +28 -7
- package/src/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +11 -8
- package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
- package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
- package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
- 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 +11 -31
- package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +35 -32
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +179 -25
- package/src/audit/languageAnalysisEngine/report/models/reportLibraryModel.ts +3 -3
- package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +18 -11
- package/src/audit/languageAnalysisEngine/report/models/reportOutputModel.ts +29 -0
- package/src/audit/languageAnalysisEngine/report/models/reportSeverityModel.ts +12 -3
- package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +20 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +50 -18
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +88 -66
- package/src/audit/languageAnalysisEngine/sendSnapshot.js +78 -3
- package/src/audit/save.js +32 -0
- package/src/commands/audit/auditController.ts +23 -15
- package/src/commands/audit/help.ts +24 -1
- package/src/commands/audit/processAudit.ts +7 -4
- package/src/commands/audit/saveFile.ts +5 -1
- package/src/commands/scan/processScan.js +2 -1
- package/src/commands/scan/sca/scaAnalysis.js +70 -29
- package/src/common/HTTPClient.js +72 -25
- package/src/common/errorHandling.ts +10 -1
- package/src/common/versionChecker.ts +24 -5
- package/src/constants/constants.js +13 -3
- package/src/constants/locales.js +15 -12
- package/src/constants.js +9 -4
- package/src/index.ts +5 -3
- package/src/lambda/analytics.ts +9 -0
- package/src/lambda/arn.ts +2 -1
- package/src/lambda/lambda.ts +37 -17
- package/src/lambda/types.ts +35 -0
- package/src/lambda/utils.ts +2 -7
- package/src/sbom/generateSbom.ts +1 -1
- package/src/scaAnalysis/common/formatMessage.js +51 -1
- package/src/scaAnalysis/common/treeUpload.js +1 -6
- package/src/scaAnalysis/go/goAnalysis.js +19 -0
- package/src/scaAnalysis/go/goParseDeps.js +203 -0
- package/src/scaAnalysis/go/goReadDepFile.js +30 -0
- package/src/scaAnalysis/java/analysis.js +15 -32
- package/src/scaAnalysis/java/index.js +6 -6
- package/src/scaAnalysis/java/javaBuildDepsParser.js +15 -2
- 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 +49 -0
- package/src/scaAnalysis/python/index.js +11 -0
- package/src/scaAnalysis/ruby/analysis.js +282 -0
- package/src/scaAnalysis/ruby/index.js +11 -0
- package/src/scan/autoDetection.js +11 -7
- package/src/scan/fileUtils.js +27 -8
- package/src/scan/formatScanOutput.ts +26 -18
- package/src/scan/models/groupedResultsModel.ts +3 -3
- package/src/scan/models/resultContentModel.ts +1 -1
- package/src/scan/models/scanResultsModel.ts +5 -2
- package/src/scan/populateProjectIdAndProjectName.js +3 -1
- package/src/scan/scan.ts +8 -6
- package/src/scan/scanConfig.js +5 -1
- package/src/scan/scanController.js +30 -9
- package/src/scan/scanResults.js +31 -10
- package/src/utils/commonApi.js +4 -1
- package/src/utils/filterProjectPath.js +6 -2
- package/src/utils/oraWrapper.js +6 -1
|
@@ -1,20 +1,40 @@
|
|
|
1
1
|
const autoDetection = require('../../../scan/autoDetection')
|
|
2
|
-
const
|
|
3
|
-
const
|
|
2
|
+
const javaAnalysis = require('../../../scaAnalysis/java')
|
|
3
|
+
const treeUpload = require('../../../scaAnalysis/common/treeUpload')
|
|
4
4
|
const {
|
|
5
5
|
manualDetectAuditFilesAndLanguages
|
|
6
6
|
} = require('../../../scan/autoDetection')
|
|
7
|
-
const
|
|
7
|
+
const auditController = require('../../audit/auditController')
|
|
8
8
|
const {
|
|
9
|
-
supportedLanguages: { JAVA }
|
|
9
|
+
supportedLanguages: { JAVA, GO, PYTHON, RUBY, JAVASCRIPT, NODE, PHP }
|
|
10
10
|
} = require('../../../audit/languageAnalysisEngine/constants')
|
|
11
|
+
const goAnalysis = require('../../../scaAnalysis/go/goAnalysis')
|
|
12
|
+
const phpAnalysis = require('../../../scaAnalysis/php/index')
|
|
13
|
+
const { rubyAnalysis } = require('../../../scaAnalysis/ruby')
|
|
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')
|
|
11
29
|
|
|
12
30
|
const processSca = async config => {
|
|
13
31
|
let filesFound
|
|
14
|
-
if (config.
|
|
15
|
-
|
|
32
|
+
if (config.file) {
|
|
33
|
+
config.file = config.file.concat('/')
|
|
34
|
+
filesFound = await manualDetectAuditFilesAndLanguages(config.file)
|
|
16
35
|
} else {
|
|
17
36
|
filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config)
|
|
37
|
+
config.file = process.cwd().concat('/')
|
|
18
38
|
}
|
|
19
39
|
|
|
20
40
|
// files found looks like [ { javascript: [ Array ] } ]
|
|
@@ -24,27 +44,32 @@ const processSca = async config => {
|
|
|
24
44
|
if (filesFound.length === 1) {
|
|
25
45
|
switch (Object.keys(filesFound[0])[0]) {
|
|
26
46
|
case JAVA:
|
|
27
|
-
messageToSend =
|
|
47
|
+
messageToSend = javaAnalysis.javaAnalysis(config, filesFound[0])
|
|
28
48
|
config.language = JAVA
|
|
29
49
|
break
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
case JAVASCRIPT:
|
|
51
|
+
messageToSend = await javascriptAnalysis.jsAnalysis(
|
|
52
|
+
config,
|
|
53
|
+
filesFound[0]
|
|
54
|
+
)
|
|
55
|
+
config.language = NODE
|
|
56
|
+
break
|
|
57
|
+
case PYTHON:
|
|
58
|
+
messageToSend = pythonAnalysis(config, filesFound[0])
|
|
59
|
+
config.language = PYTHON
|
|
60
|
+
break
|
|
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
|
|
69
|
+
case GO:
|
|
70
|
+
messageToSend = goAnalysis.goAnalysis(config, filesFound[0])
|
|
71
|
+
config.language = GO
|
|
72
|
+
break
|
|
48
73
|
default:
|
|
49
74
|
//something is wrong
|
|
50
75
|
console.log('language detected not supported')
|
|
@@ -52,17 +77,33 @@ const processSca = async config => {
|
|
|
52
77
|
}
|
|
53
78
|
|
|
54
79
|
if (!config.applicationId) {
|
|
55
|
-
config.applicationId = await dealWithNoAppId(config)
|
|
80
|
+
config.applicationId = await auditController.dealWithNoAppId(config)
|
|
56
81
|
}
|
|
57
82
|
//send message to TS
|
|
58
|
-
|
|
59
|
-
|
|
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)
|
|
60
101
|
} else {
|
|
61
102
|
if (filesFound.length === 0) {
|
|
62
103
|
console.log('no compatible dependency files detected. Continuing...')
|
|
63
104
|
} else {
|
|
64
105
|
console.log(
|
|
65
|
-
'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'
|
|
66
107
|
)
|
|
67
108
|
}
|
|
68
109
|
}
|
package/src/common/HTTPClient.js
CHANGED
|
@@ -22,7 +22,8 @@ function HTTPClient(config) {
|
|
|
22
22
|
Authorization: authToken,
|
|
23
23
|
'API-Key': apiKey,
|
|
24
24
|
SuperAuthorization: superAuthToken,
|
|
25
|
-
'Super-API-Key': superApiKey
|
|
25
|
+
'Super-API-Key': superApiKey,
|
|
26
|
+
'User-Agent': 'contrast-cli-v2'
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -33,7 +34,7 @@ function HTTPClient(config) {
|
|
|
33
34
|
this.maybeAddCertsToRequest(config)
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
HTTPClient.prototype.maybeAddCertsToRequest = function(config) {
|
|
37
|
+
HTTPClient.prototype.maybeAddCertsToRequest = function (config) {
|
|
37
38
|
// cacert
|
|
38
39
|
const caCertFilePath = config.cacert
|
|
39
40
|
if (caCertFilePath) {
|
|
@@ -91,13 +92,30 @@ HTTPClient.prototype.getSpecificScanResult = function getSpecificScanResult(
|
|
|
91
92
|
return requestUtils.sendRequest({ method: 'get', options })
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
HTTPClient.prototype.getSpecificScanResultSarif =
|
|
95
|
+
HTTPClient.prototype.getSpecificScanResultSarif =
|
|
96
|
+
function getSpecificScanResultSarif(config, scanId) {
|
|
97
|
+
const options = _.cloneDeep(this.requestOptions)
|
|
98
|
+
options.url = createRawOutputURL(config, scanId)
|
|
99
|
+
return requestUtils.sendRequest({ method: 'get', options })
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
HTTPClient.prototype.createNewEvent = function createNewEvent(
|
|
95
103
|
config,
|
|
96
|
-
scanId
|
|
104
|
+
scanId,
|
|
105
|
+
newProject
|
|
97
106
|
) {
|
|
98
107
|
const options = _.cloneDeep(this.requestOptions)
|
|
99
|
-
options.url =
|
|
100
|
-
|
|
108
|
+
options.url = createEventCollectorURL(config, scanId)
|
|
109
|
+
|
|
110
|
+
options.body = {
|
|
111
|
+
eventSource: process.env.CODESEC_INVOCATION_ENVIRONMENT,
|
|
112
|
+
trackingProperties: {
|
|
113
|
+
projectNameSource: config.projectNameSource,
|
|
114
|
+
waitedForResults: !config.ff,
|
|
115
|
+
newProject
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return requestUtils.sendRequest({ method: 'post', options })
|
|
101
119
|
}
|
|
102
120
|
|
|
103
121
|
HTTPClient.prototype.getScanId = function getScanId(config, codeArtifactId) {
|
|
@@ -190,9 +208,6 @@ HTTPClient.prototype.catalogueCommand = function catalogueCommand(config) {
|
|
|
190
208
|
}
|
|
191
209
|
|
|
192
210
|
HTTPClient.prototype.sendSnapshot = function sendSnapshot(requestBody, config) {
|
|
193
|
-
if (config.language.toUpperCase() === 'RUBY') {
|
|
194
|
-
//console.log('sendSnapshot requestBody', requestBody.snapshot.ruby)
|
|
195
|
-
}
|
|
196
211
|
const options = _.cloneDeep(this.requestOptions)
|
|
197
212
|
let url = createSnapshotURL(config)
|
|
198
213
|
options.url = url
|
|
@@ -210,17 +225,24 @@ HTTPClient.prototype.getReportById = function getReportById(config, reportId) {
|
|
|
210
225
|
return requestUtils.sendRequest({ method: 'get', options })
|
|
211
226
|
}
|
|
212
227
|
|
|
213
|
-
HTTPClient.prototype.
|
|
228
|
+
HTTPClient.prototype.getReportStatusById = function getReportStatusById(
|
|
214
229
|
config,
|
|
215
|
-
|
|
230
|
+
snapshotId
|
|
216
231
|
) {
|
|
217
232
|
const options = _.cloneDeep(this.requestOptions)
|
|
218
|
-
options.url =
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
return requestUtils.sendRequest({ method: 'put', options })
|
|
233
|
+
options.url = createSpecificReportStatusURL(config, snapshotId)
|
|
234
|
+
return requestUtils.sendRequest({ method: 'get', options })
|
|
222
235
|
}
|
|
223
236
|
|
|
237
|
+
HTTPClient.prototype.getLibraryVulnerabilities =
|
|
238
|
+
function getLibraryVulnerabilities(config, requestBody) {
|
|
239
|
+
const options = _.cloneDeep(this.requestOptions)
|
|
240
|
+
options.url = createLibraryVulnerabilitiesUrl(config)
|
|
241
|
+
options.body = requestBody
|
|
242
|
+
|
|
243
|
+
return requestUtils.sendRequest({ method: 'put', options })
|
|
244
|
+
}
|
|
245
|
+
|
|
224
246
|
HTTPClient.prototype.getAppId = function getAppId(config) {
|
|
225
247
|
const options = _.cloneDeep(this.requestOptions)
|
|
226
248
|
let url = createAppNameUrl(config)
|
|
@@ -295,17 +317,13 @@ HTTPClient.prototype.getScanResources = async function getScanResources(
|
|
|
295
317
|
return requestUtils.sendRequest({ method: 'get', options })
|
|
296
318
|
}
|
|
297
319
|
|
|
298
|
-
HTTPClient.prototype.getFunctionScanResults =
|
|
299
|
-
config,
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
functionArn
|
|
303
|
-
) {
|
|
304
|
-
const url = createScanResultsGetUrl(config, params, scanId, functionArn)
|
|
305
|
-
const options = { ...this.requestOptions, url }
|
|
320
|
+
HTTPClient.prototype.getFunctionScanResults =
|
|
321
|
+
async function getFunctionScanResults(config, params, scanId, functionArn) {
|
|
322
|
+
const url = createScanResultsGetUrl(config, params, scanId, functionArn)
|
|
323
|
+
const options = { ...this.requestOptions, url }
|
|
306
324
|
|
|
307
|
-
|
|
308
|
-
}
|
|
325
|
+
return requestUtils.sendRequest({ method: 'get', options })
|
|
326
|
+
}
|
|
309
327
|
|
|
310
328
|
HTTPClient.prototype.checkLibrary = function checkLibrary(data) {
|
|
311
329
|
const options = _.cloneDeep(this.requestOptions)
|
|
@@ -321,6 +339,27 @@ HTTPClient.prototype.getSbom = function getSbom(config) {
|
|
|
321
339
|
return requestUtils.sendRequest({ method: 'get', options })
|
|
322
340
|
}
|
|
323
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
|
+
|
|
349
|
+
// analytics
|
|
350
|
+
|
|
351
|
+
HTTPClient.prototype.postAnalyticsFunction = function (config, provider, body) {
|
|
352
|
+
const url = createAnalyticsFunctionPostUrl(config, provider)
|
|
353
|
+
const options = { ...this.requestOptions, body, url }
|
|
354
|
+
|
|
355
|
+
return requestUtils.sendRequest({ method: 'post', options })
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const createAnalyticsFunctionPostUrl = (config, provider) => {
|
|
359
|
+
const url = getServerlessHost(config)
|
|
360
|
+
return `${url}/organizations/${config.organizationId}/providers/${provider}/analytics`
|
|
361
|
+
}
|
|
362
|
+
|
|
324
363
|
// scan
|
|
325
364
|
const createGetScanIdURL = config => {
|
|
326
365
|
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/scans/`
|
|
@@ -350,6 +389,10 @@ function createScanProjectUrl(config) {
|
|
|
350
389
|
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}`
|
|
351
390
|
}
|
|
352
391
|
|
|
392
|
+
const createEventCollectorURL = (config, scanId) => {
|
|
393
|
+
return `${config.host}/Contrast/api/sast/organizations/${config.organizationId}/projects/${config.projectId}/scans/${scanId}/events`
|
|
394
|
+
}
|
|
395
|
+
|
|
353
396
|
const createGlobalPropertiesUrl = protocol => {
|
|
354
397
|
return `${protocol}/Contrast/api/ng/global/properties`
|
|
355
398
|
}
|
|
@@ -384,6 +427,10 @@ function createSpecificReportWithProdUrl(config, reportId) {
|
|
|
384
427
|
)
|
|
385
428
|
}
|
|
386
429
|
|
|
430
|
+
function createSpecificReportStatusURL(config, reportId) {
|
|
431
|
+
return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/${config.applicationId}/snapshots/${reportId}/status`
|
|
432
|
+
}
|
|
433
|
+
|
|
387
434
|
function createDataUrl() {
|
|
388
435
|
return `https://ardy.contrastsecurity.com/production`
|
|
389
436
|
}
|
|
@@ -64,6 +64,14 @@ const proxyError = () => {
|
|
|
64
64
|
generalError('proxyErrorHeader', 'proxyErrorMessage')
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
const maxAppError = () => {
|
|
68
|
+
generalError(
|
|
69
|
+
'No applications remaining',
|
|
70
|
+
'You have reached the maximum number of application you can create.'
|
|
71
|
+
)
|
|
72
|
+
process.exit(1)
|
|
73
|
+
}
|
|
74
|
+
|
|
67
75
|
const failOptionError = () => {
|
|
68
76
|
console.log(
|
|
69
77
|
'\n ******************************** ' +
|
|
@@ -140,5 +148,6 @@ export {
|
|
|
140
148
|
findCommandOnError,
|
|
141
149
|
snapshotFailureError,
|
|
142
150
|
vulnerabilitiesFailureError,
|
|
143
|
-
reportFailureError
|
|
151
|
+
reportFailureError,
|
|
152
|
+
maxAppError
|
|
144
153
|
}
|
|
@@ -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(
|
|
@@ -37,5 +56,5 @@ export async function findLatestCLIVersion(updateMessageHidden: boolean) {
|
|
|
37
56
|
}
|
|
38
57
|
|
|
39
58
|
export async function isCorrectNodeVersion(currentVersion: string) {
|
|
40
|
-
return semver.satisfies(currentVersion, '>=16
|
|
59
|
+
return semver.satisfies(currentVersion, '>=16')
|
|
41
60
|
}
|
|
@@ -13,13 +13,18 @@ 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'
|
|
20
20
|
const MEDIUM_COLOUR = '#f1c232'
|
|
21
|
-
const LOW_COLOUR = '#
|
|
21
|
+
const LOW_COLOUR = '#b7b7b7'
|
|
22
22
|
const NOTE_COLOUR = '#999999'
|
|
23
|
+
const CRITICAL_PRIORITY = 1
|
|
24
|
+
const HIGH_PRIORITY = 2
|
|
25
|
+
const MEDIUM_PRIORITY = 3
|
|
26
|
+
const LOW_PRIORITY = 4
|
|
27
|
+
const NOTE_PRIORITY = 5
|
|
23
28
|
|
|
24
29
|
const AUTH_UI_URL = 'https://cli-auth.contrastsecurity.com'
|
|
25
30
|
const AUTH_CALLBACK_URL = 'https://cli-auth-api.contrastsecurity.com'
|
|
@@ -43,5 +48,10 @@ module.exports = {
|
|
|
43
48
|
MEDIUM_COLOUR,
|
|
44
49
|
LOW_COLOUR,
|
|
45
50
|
NOTE_COLOUR,
|
|
46
|
-
CE_URL
|
|
51
|
+
CE_URL,
|
|
52
|
+
CRITICAL_PRIORITY,
|
|
53
|
+
HIGH_PRIORITY,
|
|
54
|
+
MEDIUM_PRIORITY,
|
|
55
|
+
LOW_PRIORITY,
|
|
56
|
+
NOTE_PRIORITY
|
|
47
57
|
}
|
package/src/constants/locales.js
CHANGED
|
@@ -15,7 +15,7 @@ const en_locales = () => {
|
|
|
15
15
|
catchErrorMessage: 'Contrast UI error: ',
|
|
16
16
|
dependenciesNote:
|
|
17
17
|
'Please Note: We currently only support projects with one .csproj AND *.package.lock.json',
|
|
18
|
-
languageAnalysisFailureMessage: 'SCA
|
|
18
|
+
languageAnalysisFailureMessage: 'SCA audit Failure',
|
|
19
19
|
languageAnalysisFactoryFailureHeader: 'FAIL',
|
|
20
20
|
libraryAnalysisError:
|
|
21
21
|
'Please ensure the language parameter is set in accordance to the language specified on the project path.\nContrast CLI must be run in the same directory as the project manifest file OR the project_path parameter must be used to identify the directory containing the project manifest file.\n\nFor further information please read our usage guide, which can be accessed with the following command:\n\ncontrast-cli --help',
|
|
@@ -118,7 +118,7 @@ const en_locales = () => {
|
|
|
118
118
|
'Provide this if you want to catalogue an application',
|
|
119
119
|
constantsLanguage:
|
|
120
120
|
'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',
|
|
121
|
-
|
|
121
|
+
constantsFilePath:
|
|
122
122
|
'The directory root of a project/application that you would like analyzed. Defaults to current directory.',
|
|
123
123
|
constantsSilent: 'Silences JSON output.',
|
|
124
124
|
constantsAppGroups:
|
|
@@ -137,16 +137,16 @@ const en_locales = () => {
|
|
|
137
137
|
'The ID associated with a scan project. Replace <ProjectID> with the ID for the scan project. To find the ID, select a scan project in Contrast and locate the last number in the URL.',
|
|
138
138
|
constantsReport: 'Display vulnerability information for this application',
|
|
139
139
|
constantsFail:
|
|
140
|
-
'Set the process to fail if this option is set in combination with
|
|
140
|
+
'Set the process to fail if this option is set in combination with --cve_severity.',
|
|
141
141
|
failOptionErrorMessage:
|
|
142
|
-
|
|
142
|
+
' FAIL - CVEs have been detected that match at least the cve_severity or cve_threshold option specified.',
|
|
143
143
|
constantsSeverity:
|
|
144
|
-
'
|
|
145
|
-
constantsCount:
|
|
144
|
+
'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.',
|
|
145
|
+
constantsCount: 'The number of CVEs that must be exceeded to fail a build',
|
|
146
146
|
constantsHeader: 'CodeSec by Contrast Security',
|
|
147
147
|
constantsPrerequisitesContentScanLanguages: 'Java & JavaScript supported',
|
|
148
148
|
constantsContrastContent:
|
|
149
|
-
|
|
149
|
+
"Use the 'contrast' command for fast and accurate security analysis of your applications and APIs (Java, JavaScript and .NET ) as well as serverless functions (AWS lambda, Java and Python).",
|
|
150
150
|
constantsUsageGuideContentRecommendation:
|
|
151
151
|
'Our recommendation is that this is invoked as part of a CI pipeline so that running the cli is automated as part of your build process.',
|
|
152
152
|
constantsPrerequisitesHeader: 'Pre-requisites',
|
|
@@ -249,7 +249,7 @@ const en_locales = () => {
|
|
|
249
249
|
scanLabel:
|
|
250
250
|
"adds a label to the scan - defaults to 'Started by CLI tool at current date'",
|
|
251
251
|
constantsIgnoreDev:
|
|
252
|
-
'
|
|
252
|
+
'Excludes developer dependencies from the output. By default all dependencies are included.',
|
|
253
253
|
constantsCommands: 'Commands',
|
|
254
254
|
constantsScanOptions: 'Scan Options',
|
|
255
255
|
sbomError: 'All required parameters are not present.',
|
|
@@ -356,6 +356,7 @@ const en_locales = () => {
|
|
|
356
356
|
scanZipError:
|
|
357
357
|
'A .zip archive can be used for Javascript Scan. Archive found %s does not contain .JS files for Scan.',
|
|
358
358
|
fileNotExist: 'File specified does not exist, please check and try again.',
|
|
359
|
+
scanFileIsEmpty: 'File specified is empty. Please choose another.',
|
|
359
360
|
fileHasWhiteSpacesError:
|
|
360
361
|
'File cannot have spaces, please rename or choose another file to Scan.',
|
|
361
362
|
zipFileException: 'Error reading zip file',
|
|
@@ -392,12 +393,13 @@ const en_locales = () => {
|
|
|
392
393
|
auditOptionsIgnoreDevDependenciesDescription: 'ignores DevDependencies',
|
|
393
394
|
auditOptionsSave: '-s, --save',
|
|
394
395
|
auditOptionsSaveDescription:
|
|
395
|
-
'saves the output in specified format
|
|
396
|
+
'saves the output in specified format, options: sbom',
|
|
396
397
|
scanNotCompleted:
|
|
397
398
|
'Scan not completed. Check for framework and language support here: %s',
|
|
398
|
-
|
|
399
|
+
auditNotCompleted: 'audit not completed. Please try again',
|
|
400
|
+
scanNoVulnerabilitiesFound: '🎉 No vulnerabilities found.',
|
|
399
401
|
scanNoVulnerabilitiesFoundSecureCode: '👍 Your code looks secure.',
|
|
400
|
-
scanNoVulnerabilitiesFoundGoodWork: '
|
|
402
|
+
scanNoVulnerabilitiesFoundGoodWork: ' Keep up the good work.',
|
|
401
403
|
scanNoFiletypeSpecifiedForSave:
|
|
402
404
|
'Please specify file type to save results to, accepted value is SARIF',
|
|
403
405
|
auditSBOMSaveSuccess:
|
|
@@ -412,7 +414,8 @@ const en_locales = () => {
|
|
|
412
414
|
auditReportFail: 'Report Retrieval Failed, please try again',
|
|
413
415
|
auditReportSuccessMessage: 'Report successfully retrieved',
|
|
414
416
|
auditReportFailureMessage: 'Unable to generate library report',
|
|
415
|
-
auditSCAAnalysisBegins: 'Contrast SCA
|
|
417
|
+
auditSCAAnalysisBegins: 'Contrast SCA audit started',
|
|
418
|
+
auditSCAAnalysisComplete: 'Contrast SCA audit complete',
|
|
416
419
|
...lambda
|
|
417
420
|
}
|
|
418
421
|
}
|
package/src/constants.js
CHANGED
|
@@ -49,7 +49,6 @@ const scanOptionDefinitions = [
|
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
name: 'project-path',
|
|
52
|
-
alias: 'i',
|
|
53
52
|
description:
|
|
54
53
|
'{bold ' +
|
|
55
54
|
i18n.__('constantsOptional') +
|
|
@@ -212,13 +211,14 @@ const auditOptionDefinitions = [
|
|
|
212
211
|
i18n.__('constantsApplicationName')
|
|
213
212
|
},
|
|
214
213
|
{
|
|
215
|
-
name: '
|
|
216
|
-
|
|
214
|
+
name: 'file',
|
|
215
|
+
alias: 'f',
|
|
216
|
+
defaultValue: process.cwd(),
|
|
217
217
|
description:
|
|
218
218
|
'{bold ' +
|
|
219
219
|
i18n.__('constantsOptional') +
|
|
220
220
|
'}: ' +
|
|
221
|
-
i18n.__('
|
|
221
|
+
i18n.__('constantsFilePath')
|
|
222
222
|
},
|
|
223
223
|
{
|
|
224
224
|
name: 'app-groups',
|
|
@@ -334,6 +334,11 @@ const auditOptionDefinitions = [
|
|
|
334
334
|
i18n.__('constantsOptional') +
|
|
335
335
|
'}: ' +
|
|
336
336
|
i18n.__('auditOptionsSaveDescription')
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
name: 'experimental',
|
|
340
|
+
alias: 'e',
|
|
341
|
+
type: Boolean
|
|
337
342
|
}
|
|
338
343
|
]
|
|
339
344
|
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
1
3
|
import commandLineArgs from 'command-line-args'
|
|
2
4
|
import { processAudit } from './commands/audit/processAudit'
|
|
3
5
|
import { processAuth } from './commands/auth/auth'
|
|
@@ -44,7 +46,7 @@ const start = async () => {
|
|
|
44
46
|
argvMain.includes('--version')
|
|
45
47
|
) {
|
|
46
48
|
console.log(APP_VERSION)
|
|
47
|
-
await findLatestCLIVersion(config
|
|
49
|
+
await findLatestCLIVersion(config)
|
|
48
50
|
return
|
|
49
51
|
}
|
|
50
52
|
|
|
@@ -52,8 +54,8 @@ const start = async () => {
|
|
|
52
54
|
config.set('numOfRuns', config.get('numOfRuns') + 1)
|
|
53
55
|
|
|
54
56
|
// @ts-ignore
|
|
55
|
-
if (config.get('numOfRuns') >=
|
|
56
|
-
await findLatestCLIVersion(config
|
|
57
|
+
if (config.get('numOfRuns') >= 1) {
|
|
58
|
+
await findLatestCLIVersion(config)
|
|
57
59
|
config.set('numOfRuns', 0)
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { getHttpClient } from '../utils/commonApi'
|
|
2
|
+
import { getAuth } from '../utils/paramsUtil/paramHandler'
|
|
3
|
+
import { AnalyticsOption } from './types'
|
|
4
|
+
|
|
5
|
+
export const postAnalytics = (data: AnalyticsOption, provider = 'aws') => {
|
|
6
|
+
const config = getAuth()
|
|
7
|
+
const client = getHttpClient(config)
|
|
8
|
+
return client.postAnalyticsFunction(config, provider, data)
|
|
9
|
+
}
|
package/src/lambda/arn.ts
CHANGED
|
@@ -10,7 +10,8 @@ type ARN = {
|
|
|
10
10
|
resourceId?: string
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const ARN_REGEX =
|
|
13
|
+
const ARN_REGEX =
|
|
14
|
+
/arn:(?<partition>[^:\n]*):(?<service>[^:\n]*):(?<region>[^:\n]*):(?<accountId>[^:\n]*):(?<ignore>(?<resource>[^:/\n]*)[:/])?(?<resourceId>.*)/
|
|
14
15
|
|
|
15
16
|
const parseARN = (arn: string | undefined) => {
|
|
16
17
|
if (!arn) {
|
package/src/lambda/lambda.ts
CHANGED
|
@@ -14,18 +14,8 @@ import { printResults } from './utils'
|
|
|
14
14
|
import { getAllLambdas, printAvailableLambdas } from './lambdaUtils'
|
|
15
15
|
import { sleep } from '../utils/requestUtils'
|
|
16
16
|
import ora from '../utils/oraWrapper'
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
functionName?: string
|
|
20
|
-
listFunctions?: boolean
|
|
21
|
-
region?: string
|
|
22
|
-
endpointUrl?: string
|
|
23
|
-
profile?: string
|
|
24
|
-
help?: boolean
|
|
25
|
-
verbose?: boolean
|
|
26
|
-
jsonOutput?: boolean
|
|
27
|
-
_unknown?: string[]
|
|
28
|
-
}
|
|
17
|
+
import { postAnalytics } from './analytics'
|
|
18
|
+
import { LambdaOptions, AnalyticsOption, StatusType, EventType } from './types'
|
|
29
19
|
|
|
30
20
|
type ApiParams = {
|
|
31
21
|
organizationId: string
|
|
@@ -74,10 +64,20 @@ const getLambdaOptions = (argv: string[]) => {
|
|
|
74
64
|
}
|
|
75
65
|
|
|
76
66
|
const processLambda = async (argv: string[]) => {
|
|
67
|
+
let errorMsg
|
|
68
|
+
let scanInfo: { functionArn: string; scanId: string } | undefined
|
|
69
|
+
const commandSessionId = Date.now().toString(36)
|
|
77
70
|
try {
|
|
78
71
|
const lambdaOptions = getLambdaOptions(argv)
|
|
79
72
|
const { help } = lambdaOptions
|
|
80
|
-
|
|
73
|
+
const startCommandAnalytics: AnalyticsOption = {
|
|
74
|
+
arguments: lambdaOptions,
|
|
75
|
+
sessionId: commandSessionId,
|
|
76
|
+
eventType: EventType.START
|
|
77
|
+
}
|
|
78
|
+
postAnalytics(startCommandAnalytics).catch((error: Error) => {
|
|
79
|
+
/* ignore */
|
|
80
|
+
})
|
|
81
81
|
if (help) {
|
|
82
82
|
return handleLambdaHelp()
|
|
83
83
|
}
|
|
@@ -87,15 +87,33 @@ const processLambda = async (argv: string[]) => {
|
|
|
87
87
|
if (lambdaOptions.listFunctions) {
|
|
88
88
|
await getAvailableFunctions(lambdaOptions)
|
|
89
89
|
} else {
|
|
90
|
-
await actualProcessLambda(lambdaOptions)
|
|
90
|
+
scanInfo = await actualProcessLambda(lambdaOptions)
|
|
91
91
|
}
|
|
92
92
|
} catch (error) {
|
|
93
93
|
if (error instanceof CliError) {
|
|
94
|
-
|
|
94
|
+
errorMsg = error.getErrorMessage()
|
|
95
95
|
} else if (error instanceof Error) {
|
|
96
|
-
|
|
96
|
+
errorMsg = error.message
|
|
97
|
+
}
|
|
98
|
+
} finally {
|
|
99
|
+
const endCommandAnalytics: AnalyticsOption = {
|
|
100
|
+
sessionId: commandSessionId,
|
|
101
|
+
eventType: EventType.END,
|
|
102
|
+
status: errorMsg ? StatusType.FAILED : StatusType.SUCCESS
|
|
103
|
+
}
|
|
104
|
+
if (errorMsg) {
|
|
105
|
+
endCommandAnalytics.errorMsg = errorMsg
|
|
106
|
+
console.error(errorMsg)
|
|
107
|
+
}
|
|
108
|
+
if (scanInfo) {
|
|
109
|
+
endCommandAnalytics.scanFunctionData = scanInfo
|
|
110
|
+
}
|
|
111
|
+
await postAnalytics(endCommandAnalytics).catch((error: Error) => {
|
|
112
|
+
/* ignore */
|
|
113
|
+
})
|
|
114
|
+
if (errorMsg) {
|
|
115
|
+
process.exit(1)
|
|
97
116
|
}
|
|
98
|
-
process.exit(1)
|
|
99
117
|
}
|
|
100
118
|
}
|
|
101
119
|
|
|
@@ -162,6 +180,8 @@ const actualProcessLambda = async (lambdaOptions: LambdaOptions) => {
|
|
|
162
180
|
if (results?.length) {
|
|
163
181
|
printResults(results)
|
|
164
182
|
}
|
|
183
|
+
|
|
184
|
+
return { functionArn, scanId }
|
|
165
185
|
}
|
|
166
186
|
|
|
167
187
|
const validateRequiredLambdaParams = (options: LambdaOptions) => {
|