@contrast/contrast 1.0.4 → 1.0.7
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 -3
- package/dist/audit/autodetection/autoDetectLanguage.js +32 -0
- package/dist/audit/catalogueApplication/catalogueApplication.js +2 -11
- 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/languageAnalysisFactory.js +6 -2
- package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +39 -1
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +69 -30
- 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 +13 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +2 -2
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +56 -45
- package/dist/audit/languageAnalysisEngine/sendSnapshot.js +65 -17
- package/dist/commands/audit/auditConfig.js +8 -2
- package/dist/commands/audit/auditController.js +9 -3
- package/dist/commands/audit/processAudit.js +1 -1
- package/dist/commands/scan/processScan.js +7 -4
- package/dist/commands/scan/sca/scaAnalysis.js +60 -0
- package/dist/common/HTTPClient.js +50 -16
- package/dist/common/errorHandling.js +11 -16
- package/dist/common/versionChecker.js +1 -1
- package/dist/constants/constants.js +24 -2
- package/dist/constants/locales.js +31 -36
- package/dist/constants.js +20 -0
- package/dist/lambda/analytics.js +11 -0
- package/dist/lambda/lambda.js +35 -4
- package/dist/lambda/types.js +13 -0
- package/dist/scaAnalysis/common/formatMessage.js +35 -0
- package/dist/scaAnalysis/common/treeUpload.js +29 -0
- package/dist/scaAnalysis/go/goAnalysis.js +17 -0
- package/dist/scaAnalysis/go/goParseDeps.js +158 -0
- package/dist/scaAnalysis/go/goReadDepFile.js +23 -0
- package/dist/scaAnalysis/java/analysis.js +105 -0
- package/dist/scaAnalysis/java/index.js +18 -0
- package/dist/scaAnalysis/java/javaBuildDepsParser.js +339 -0
- package/dist/scaAnalysis/python/analysis.js +41 -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 +50 -1
- package/dist/scan/fileUtils.js +80 -1
- package/dist/scan/formatScanOutput.js +213 -0
- package/dist/scan/help.js +3 -1
- package/dist/scan/models/groupedResultsModel.js +2 -1
- package/dist/scan/models/scanResultsModel.js +3 -1
- package/dist/scan/populateProjectIdAndProjectName.js +2 -1
- package/dist/scan/scan.js +6 -99
- package/dist/scan/scanConfig.js +6 -1
- package/dist/scan/scanController.js +26 -7
- package/dist/scan/scanResults.js +20 -20
- package/dist/utils/commonApi.js +4 -1
- package/dist/utils/oraWrapper.js +5 -1
- package/package.json +12 -7
- package/src/audit/autodetection/autoDetectLanguage.ts +40 -0
- package/src/audit/catalogueApplication/catalogueApplication.js +3 -16
- 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/languageAnalysisFactory.js +17 -5
- package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +76 -3
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +122 -40
- package/src/audit/languageAnalysisEngine/report/models/reportLibraryModel.ts +3 -3
- package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +15 -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 +16 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +3 -3
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +87 -65
- package/src/audit/languageAnalysisEngine/sendSnapshot.js +78 -25
- package/src/commands/audit/auditConfig.ts +12 -3
- package/src/commands/audit/auditController.ts +9 -3
- package/src/commands/audit/processAudit.ts +4 -1
- package/src/commands/scan/processScan.js +10 -4
- package/src/commands/scan/sca/scaAnalysis.js +83 -0
- package/src/common/HTTPClient.js +65 -25
- package/src/common/errorHandling.ts +14 -22
- package/src/common/versionChecker.ts +1 -1
- package/src/constants/constants.js +24 -2
- package/src/constants/locales.js +33 -50
- package/src/constants.js +22 -0
- 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/scaAnalysis/common/formatMessage.js +38 -0
- package/src/scaAnalysis/common/treeUpload.js +30 -0
- package/src/scaAnalysis/go/goAnalysis.js +19 -0
- package/src/scaAnalysis/go/goParseDeps.js +203 -0
- package/src/scaAnalysis/go/goReadDepFile.js +32 -0
- package/src/scaAnalysis/java/analysis.js +142 -0
- package/src/scaAnalysis/java/index.js +21 -0
- package/src/scaAnalysis/java/javaBuildDepsParser.js +404 -0
- package/src/scaAnalysis/python/analysis.js +48 -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 +58 -1
- package/src/scan/fileUtils.js +99 -1
- package/src/scan/formatScanOutput.ts +249 -0
- package/src/scan/help.js +3 -1
- package/src/scan/models/groupedResultsModel.ts +7 -5
- package/src/scan/models/resultContentModel.ts +2 -2
- package/src/scan/models/scanResultsModel.ts +5 -2
- package/src/scan/populateProjectIdAndProjectName.js +3 -1
- package/src/scan/scan.ts +8 -136
- package/src/scan/scanConfig.js +5 -1
- package/src/scan/scanController.js +30 -10
- package/src/scan/scanResults.js +31 -18
- package/src/utils/commonApi.js +4 -1
- package/src/utils/oraWrapper.js +6 -1
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,20 @@ HTTPClient.prototype.getSbom = function getSbom(config) {
|
|
|
321
339
|
return requestUtils.sendRequest({ method: 'get', options })
|
|
322
340
|
}
|
|
323
341
|
|
|
342
|
+
// analytics
|
|
343
|
+
|
|
344
|
+
HTTPClient.prototype.postAnalyticsFunction = function (config, provider, body) {
|
|
345
|
+
const url = createAnalyticsFunctionPostUrl(config, provider)
|
|
346
|
+
const options = { ...this.requestOptions, body, url }
|
|
347
|
+
|
|
348
|
+
return requestUtils.sendRequest({ method: 'post', options })
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const createAnalyticsFunctionPostUrl = (config, provider) => {
|
|
352
|
+
const url = getServerlessHost(config)
|
|
353
|
+
return `${url}/organizations/${config.organizationId}/providers/${provider}/analytics`
|
|
354
|
+
}
|
|
355
|
+
|
|
324
356
|
// scan
|
|
325
357
|
const createGetScanIdURL = config => {
|
|
326
358
|
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/scans/`
|
|
@@ -350,6 +382,10 @@ function createScanProjectUrl(config) {
|
|
|
350
382
|
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}`
|
|
351
383
|
}
|
|
352
384
|
|
|
385
|
+
const createEventCollectorURL = (config, scanId) => {
|
|
386
|
+
return `${config.host}/Contrast/api/sast/organizations/${config.organizationId}/projects/${config.projectId}/scans/${scanId}/events`
|
|
387
|
+
}
|
|
388
|
+
|
|
353
389
|
const createGlobalPropertiesUrl = protocol => {
|
|
354
390
|
return `${protocol}/Contrast/api/ng/global/properties`
|
|
355
391
|
}
|
|
@@ -384,6 +420,10 @@ function createSpecificReportWithProdUrl(config, reportId) {
|
|
|
384
420
|
)
|
|
385
421
|
}
|
|
386
422
|
|
|
423
|
+
function createSpecificReportStatusURL(config, reportId) {
|
|
424
|
+
return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/${config.applicationId}/snapshots/${reportId}/status`
|
|
425
|
+
}
|
|
426
|
+
|
|
387
427
|
function createDataUrl() {
|
|
388
428
|
return `https://ardy.contrastsecurity.com/production`
|
|
389
429
|
}
|
|
@@ -27,30 +27,15 @@ const libraryAnalysisError = () => {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
const snapshotFailureError = () => {
|
|
30
|
-
console.log(
|
|
31
|
-
'\n ******************************** ' +
|
|
32
|
-
i18n.__('snapshotFailureHeader') +
|
|
33
|
-
' *********************************\n' +
|
|
34
|
-
i18n.__('snapshotFailureMessage')
|
|
35
|
-
)
|
|
30
|
+
console.log(i18n.__('snapshotFailureMessage'))
|
|
36
31
|
}
|
|
37
32
|
|
|
38
33
|
const vulnerabilitiesFailureError = () => {
|
|
39
|
-
console.log(
|
|
40
|
-
'\n ******************************** ' +
|
|
41
|
-
i18n.__('snapshotFailureHeader') +
|
|
42
|
-
' *********************************\n' +
|
|
43
|
-
i18n.__('vulnerabilitiesFailureMessage')
|
|
44
|
-
)
|
|
34
|
+
console.log(i18n.__('vulnerabilitiesFailureMessage'))
|
|
45
35
|
}
|
|
46
36
|
|
|
47
37
|
const reportFailureError = () => {
|
|
48
|
-
console.log(
|
|
49
|
-
'\n ******************************** ' +
|
|
50
|
-
i18n.__('snapshotFailureHeader') +
|
|
51
|
-
' *********************************\n' +
|
|
52
|
-
i18n.__('reportFailureMessage')
|
|
53
|
-
)
|
|
38
|
+
console.log(i18n.__('auditReportFailureMessage'))
|
|
54
39
|
}
|
|
55
40
|
|
|
56
41
|
const genericError = (missingCliOption: string) => {
|
|
@@ -79,8 +64,12 @@ const proxyError = () => {
|
|
|
79
64
|
generalError('proxyErrorHeader', 'proxyErrorMessage')
|
|
80
65
|
}
|
|
81
66
|
|
|
82
|
-
const
|
|
83
|
-
|
|
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)
|
|
84
73
|
}
|
|
85
74
|
|
|
86
75
|
const failOptionError = () => {
|
|
@@ -152,10 +141,13 @@ export {
|
|
|
152
141
|
forbiddenError,
|
|
153
142
|
proxyError,
|
|
154
143
|
failOptionError,
|
|
155
|
-
hostWarningError,
|
|
156
144
|
generalError,
|
|
157
145
|
getErrorMessage,
|
|
158
146
|
handleResponseErrors,
|
|
159
147
|
libraryAnalysisError,
|
|
160
|
-
findCommandOnError
|
|
148
|
+
findCommandOnError,
|
|
149
|
+
snapshotFailureError,
|
|
150
|
+
vulnerabilitiesFailureError,
|
|
151
|
+
reportFailureError,
|
|
152
|
+
maxAppError
|
|
161
153
|
}
|
|
@@ -37,5 +37,5 @@ export async function findLatestCLIVersion(updateMessageHidden: boolean) {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export async function isCorrectNodeVersion(currentVersion: string) {
|
|
40
|
-
return semver.satisfies(currentVersion, '>=16
|
|
40
|
+
return semver.satisfies(currentVersion, '>=16')
|
|
41
41
|
}
|
|
@@ -13,12 +13,23 @@ 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.7'
|
|
17
17
|
const TIMEOUT = 120000
|
|
18
|
+
const HIGH_COLOUR = '#ff9900'
|
|
19
|
+
const CRITICAL_COLOUR = '#e35858'
|
|
20
|
+
const MEDIUM_COLOUR = '#f1c232'
|
|
21
|
+
const LOW_COLOUR = '#b7b7b7'
|
|
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
|
|
18
28
|
|
|
19
29
|
const AUTH_UI_URL = 'https://cli-auth.contrastsecurity.com'
|
|
20
30
|
const AUTH_CALLBACK_URL = 'https://cli-auth-api.contrastsecurity.com'
|
|
21
31
|
const SARIF_FILE = 'SARIF'
|
|
32
|
+
const CE_URL = 'https://ce.contrastsecurity.com/'
|
|
22
33
|
|
|
23
34
|
module.exports = {
|
|
24
35
|
supportedLanguages: { NODE, DOTNET, JAVA, RUBY, PYTHON, GO, PHP, JAVASCRIPT },
|
|
@@ -31,5 +42,16 @@ module.exports = {
|
|
|
31
42
|
TIMEOUT,
|
|
32
43
|
AUTH_UI_URL,
|
|
33
44
|
AUTH_CALLBACK_URL,
|
|
34
|
-
SARIF_FILE
|
|
45
|
+
SARIF_FILE,
|
|
46
|
+
HIGH_COLOUR,
|
|
47
|
+
CRITICAL_COLOUR,
|
|
48
|
+
MEDIUM_COLOUR,
|
|
49
|
+
LOW_COLOUR,
|
|
50
|
+
NOTE_COLOUR,
|
|
51
|
+
CE_URL,
|
|
52
|
+
CRITICAL_PRIORITY,
|
|
53
|
+
HIGH_PRIORITY,
|
|
54
|
+
MEDIUM_PRIORITY,
|
|
55
|
+
LOW_PRIORITY,
|
|
56
|
+
NOTE_PRIORITY
|
|
35
57
|
}
|
package/src/constants/locales.js
CHANGED
|
@@ -5,46 +5,29 @@ const en_locales = () => {
|
|
|
5
5
|
return {
|
|
6
6
|
successHeader: 'SUCCESS',
|
|
7
7
|
snapshotSuccessMessage:
|
|
8
|
-
'
|
|
8
|
+
'Please go to the Contrast UI to view your dependency tree.',
|
|
9
9
|
snapshotFailureHeader: 'FAIL',
|
|
10
|
-
snapshotFailureMessage:
|
|
11
|
-
' Unable to send library analysis to your Contrast UI.',
|
|
10
|
+
snapshotFailureMessage: 'Library analysis failed',
|
|
12
11
|
snapshotHostMessage:
|
|
13
|
-
"
|
|
14
|
-
vulnerabilitiesSuccessMessage: '
|
|
15
|
-
vulnerabilitiesFailureMessage:
|
|
16
|
-
' Unable to retrieve library vulnerabilities from Team Server.',
|
|
12
|
+
"No host supplied. Using default host 'app.contrastsecurity.com'. Please ensure this is correct.",
|
|
13
|
+
vulnerabilitiesSuccessMessage: 'Vulnerability data successfully retrieved',
|
|
14
|
+
vulnerabilitiesFailureMessage: 'Unable to retrieve library vulnerabilities',
|
|
17
15
|
catchErrorMessage: 'Contrast UI error: ',
|
|
18
16
|
dependenciesNote:
|
|
19
17
|
'Please Note: We currently only support projects with one .csproj AND *.package.lock.json',
|
|
20
|
-
languageAnalysisFailureMessage: '
|
|
18
|
+
languageAnalysisFailureMessage: 'SCA Analysis Failure',
|
|
21
19
|
languageAnalysisFactoryFailureHeader: 'FAIL',
|
|
22
|
-
projectPathParameter:
|
|
23
|
-
'Please set the %s to locate the source code for the project',
|
|
24
|
-
apiKeyParameter: 'Please set the %s to connect to the Contrast UI',
|
|
25
|
-
applicationNameParameter:
|
|
26
|
-
'Please provide a value for %s, to appear in the Contrast UI',
|
|
27
|
-
languageParameter:
|
|
28
|
-
'Please set the %s to the language of the source project. Allowable values are JAVA, DOTNET, NODE, PYTHON and RUBY.',
|
|
29
|
-
hostParameter:
|
|
30
|
-
'Please set the %s to the hostname and (optionally) the port expressed as <host>:<port> of the Contrast UI',
|
|
31
|
-
organizationIdParameter:
|
|
32
|
-
'Please set the %s to correctly identify your organization within the Contrast UI',
|
|
33
|
-
authorizationParameter:
|
|
34
|
-
'Please set the %s to your authorization header, found in the Contrast UI',
|
|
35
|
-
applicationIdParameter:
|
|
36
|
-
'Please set the %s to the value provided within the Contrast UI for the target application',
|
|
37
20
|
libraryAnalysisError:
|
|
38
|
-
'Please ensure the language parameter is set in accordance to the language specified on the project path.\
|
|
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',
|
|
39
22
|
yamlMissingParametersHeader: 'Missing Parameters',
|
|
40
23
|
yamlMissingParametersMessage:
|
|
41
|
-
'The following parameters are required: \n \
|
|
24
|
+
'The following parameters are required: \n \norganization-id \napi-key \nauthorization \nhost \nlanguage \n \nThey must be specified as a command line argument. \nFor further information please read our usage guide, which can be accessed with the following command:\ncontrast audit --help',
|
|
42
25
|
unauthenticatedErrorHeader: '401 error - Unauthenticated',
|
|
43
26
|
unauthenticatedErrorMessage:
|
|
44
|
-
'Please check the following keys are correct:\n--
|
|
27
|
+
'Please check the following keys are correct:\n--organization-id, --api-key or --authorization',
|
|
45
28
|
badRequestErrorHeader: '400 error - Bad Request',
|
|
46
29
|
badRequestErrorMessage:
|
|
47
|
-
'Please check the following key is correct: \n--
|
|
30
|
+
'Please check the following key is correct: \n--application-id',
|
|
48
31
|
badRequestCatalogueErrorMessage:
|
|
49
32
|
'The application name already exists, please use a unique name',
|
|
50
33
|
forbiddenRequestErrorHeader: '403 error - Forbidden',
|
|
@@ -53,15 +36,7 @@ const en_locales = () => {
|
|
|
53
36
|
proxyErrorHeader: '407 error - Proxy Authentication Required',
|
|
54
37
|
proxyErrorMessage:
|
|
55
38
|
'Please provide valid authentication credentials for the proxy server.',
|
|
56
|
-
|
|
57
|
-
'Connection to ContrastUI using https failed. Attempting to connect using http...',
|
|
58
|
-
setSpecifiedParameter: 'Please set the %s ',
|
|
59
|
-
catalogueFailureCommand:
|
|
60
|
-
'Failed to catalogue a new application for reason: ',
|
|
61
|
-
catalogueFailureHostCommand:
|
|
62
|
-
'Failed to catalogue a new application, please ensure you have the correct host and authentication. Error: ',
|
|
63
|
-
catalogueSuccessCommand:
|
|
64
|
-
'This application ID can now be used to send dependency data to Contrast: ',
|
|
39
|
+
catalogueSuccessCommand: 'Application Created',
|
|
65
40
|
dotnetAnalysisFailure: '.NET analysis failed because: ',
|
|
66
41
|
dotnetReadLockfile: 'Failed to read the lock file @ %s because: ',
|
|
67
42
|
dotnetParseLockfile: "Failed to parse .NET lock file @ '%s' because: ",
|
|
@@ -129,12 +104,10 @@ const en_locales = () => {
|
|
|
129
104
|
constantsOptionalForCatalogue: '(optional for catalogue)',
|
|
130
105
|
constantsRequired: '(required)',
|
|
131
106
|
constantsRequiredCatalogue: '(required for catalogue)',
|
|
132
|
-
constantsYamlPath:
|
|
133
|
-
'If you want to read params from the yaml file then enter the path to the file',
|
|
134
107
|
constantsApiKey: 'An agent API key as provided by Contrast UI',
|
|
135
108
|
constantsAuthorization:
|
|
136
|
-
'
|
|
137
|
-
constantsOrganizationId: 'The ID of your organization
|
|
109
|
+
'Authorization credentials as provided by Contrast UI',
|
|
110
|
+
constantsOrganizationId: 'The ID of your organization',
|
|
138
111
|
constantsApplicationId:
|
|
139
112
|
'The ID of the application cataloged by Contrast UI',
|
|
140
113
|
constantsHostId:
|
|
@@ -173,7 +146,7 @@ const en_locales = () => {
|
|
|
173
146
|
constantsHeader: 'CodeSec by Contrast Security',
|
|
174
147
|
constantsPrerequisitesContentScanLanguages: 'Java & JavaScript supported',
|
|
175
148
|
constantsContrastContent:
|
|
176
|
-
|
|
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).",
|
|
177
150
|
constantsUsageGuideContentRecommendation:
|
|
178
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.',
|
|
179
152
|
constantsPrerequisitesHeader: 'Pre-requisites',
|
|
@@ -253,17 +226,17 @@ const en_locales = () => {
|
|
|
253
226
|
goAnalysisError: 'GO analysis failed because: ',
|
|
254
227
|
goParseProjectFile: 'Failed to parse go mod graph output because: ',
|
|
255
228
|
mavenNotInstalledError:
|
|
256
|
-
"
|
|
229
|
+
"'mvn' is not available. Please ensure you have Maven installed and available on your path.",
|
|
257
230
|
mavenDependencyTreeNonZero:
|
|
258
231
|
'Building maven dependancy tree failed with a non 0 exit code',
|
|
259
232
|
gradleWrapperUnavailable:
|
|
260
|
-
'
|
|
233
|
+
'Gradle wrapper not found in root of project. Please ensure gradlew or gradlew.bat is in root of the project.',
|
|
261
234
|
gradleDependencyTreeNonZero:
|
|
262
235
|
"Building gradle dependancy tree failed with a non 0 exit code. \n Please check you have the correct version of Java installed to compile your project? \n If running against a muti module project ensure you are using the '--sub-project' flag",
|
|
263
236
|
yamlPathCamelCaseError:
|
|
264
|
-
'
|
|
237
|
+
'Warning: The "yamlPath" parameter will be deprecated in a future release. Please look at our documentation for further guidance.',
|
|
265
238
|
constantsSbom:
|
|
266
|
-
'
|
|
239
|
+
'Generate the Software Bill of Materials (SBOM) for the given application',
|
|
267
240
|
constantsMetadata:
|
|
268
241
|
'Define a set of key=value pairs (which conforms to RFC 2253) for specifying user-defined metadata associated with the application.',
|
|
269
242
|
constantsTags:
|
|
@@ -271,8 +244,8 @@ const en_locales = () => {
|
|
|
271
244
|
constantsCode:
|
|
272
245
|
'Add the application code this application should use in the Contrast UI',
|
|
273
246
|
constantsIgnoreCertErrors:
|
|
274
|
-
'
|
|
275
|
-
constantsSave: '
|
|
247
|
+
'For EOP users with a local Teamserver install, this will bypass the SSL certificate and recognise a self signed certificate.',
|
|
248
|
+
constantsSave: 'Saves the Scan Results SARIF to file.',
|
|
276
249
|
scanLabel:
|
|
277
250
|
"adds a label to the scan - defaults to 'Started by CLI tool at current date'",
|
|
278
251
|
constantsIgnoreDev:
|
|
@@ -291,9 +264,10 @@ const en_locales = () => {
|
|
|
291
264
|
responseMessage: 'Response: %s',
|
|
292
265
|
searchingDirectoryScan: 'Searched 3 directory levels & found: ',
|
|
293
266
|
noFileFoundScan:
|
|
294
|
-
"We
|
|
267
|
+
"We couldn't find a suitable file in your directories (we go 3 deep)",
|
|
295
268
|
specifyFileScanError:
|
|
296
269
|
'Java Scan requires a .war or .jar file. Javascript Scan requires a .js or .zip file.\nTo start a Scan enter "contrast scan -f <path-to-file>"',
|
|
270
|
+
specifyFileAuditNotFound: 'No files found for library analysis',
|
|
297
271
|
populateProjectIdMessage: 'project ID is %s',
|
|
298
272
|
genericServiceError: 'returned with status code %s',
|
|
299
273
|
projectIdError: 'Your project ID is %s please check this is correct',
|
|
@@ -342,6 +316,8 @@ const en_locales = () => {
|
|
|
342
316
|
requiredParams: 'All required parameters are not present.',
|
|
343
317
|
timeoutScan: 'Timeout set to 5 minutes.',
|
|
344
318
|
searchingScanFileDirectory: 'Searching for file to scan from %s...',
|
|
319
|
+
searchingAuditFileDirectory:
|
|
320
|
+
'Searching for package manager files from %s...',
|
|
345
321
|
scanHeader: 'Contrast Scan CLI',
|
|
346
322
|
authHeader: 'Auth',
|
|
347
323
|
lambdaHeader: 'Contrast Lambda CLI',
|
|
@@ -380,6 +356,7 @@ const en_locales = () => {
|
|
|
380
356
|
scanZipError:
|
|
381
357
|
'A .zip archive can be used for Javascript Scan. Archive found %s does not contain .JS files for Scan.',
|
|
382
358
|
fileNotExist: 'File specified does not exist, please check and try again.',
|
|
359
|
+
scanFileIsEmpty: 'File specified is empty. Please choose another.',
|
|
383
360
|
fileHasWhiteSpacesError:
|
|
384
361
|
'File cannot have spaces, please rename or choose another file to Scan.',
|
|
385
362
|
zipFileException: 'Error reading zip file',
|
|
@@ -417,7 +394,12 @@ const en_locales = () => {
|
|
|
417
394
|
auditOptionsSave: '-s, --save',
|
|
418
395
|
auditOptionsSaveDescription:
|
|
419
396
|
'saves the output in specified format Txt text, sbom',
|
|
397
|
+
scanNotCompleted:
|
|
398
|
+
'Scan not completed. Check for framework and language support here: %s',
|
|
399
|
+
auditNotCompleted: 'audit not completed. Please try again',
|
|
420
400
|
scanNoVulnerabilitiesFound: '👏 No vulnerabilities found',
|
|
401
|
+
scanNoVulnerabilitiesFoundSecureCode: '👍 Your code looks secure.',
|
|
402
|
+
scanNoVulnerabilitiesFoundGoodWork: '👏 Keep up the good work.',
|
|
421
403
|
scanNoFiletypeSpecifiedForSave:
|
|
422
404
|
'Please specify file type to save results to, accepted value is SARIF',
|
|
423
405
|
auditSBOMSaveSuccess:
|
|
@@ -430,8 +412,9 @@ const en_locales = () => {
|
|
|
430
412
|
)}`,
|
|
431
413
|
auditReportWaiting: 'Waiting for report...',
|
|
432
414
|
auditReportFail: 'Report Retrieval Failed, please try again',
|
|
433
|
-
auditReportSuccessMessage: '
|
|
434
|
-
auditReportFailureMessage: '
|
|
415
|
+
auditReportSuccessMessage: 'Report successfully retrieved',
|
|
416
|
+
auditReportFailureMessage: 'Unable to generate library report',
|
|
417
|
+
auditSCAAnalysisBegins: 'Contrast SCA analysis begins',
|
|
435
418
|
...lambda
|
|
436
419
|
}
|
|
437
420
|
}
|
package/src/constants.js
CHANGED
|
@@ -47,6 +47,15 @@ const scanOptionDefinitions = [
|
|
|
47
47
|
'}: ' +
|
|
48
48
|
i18n.__('constantsProjectId')
|
|
49
49
|
},
|
|
50
|
+
{
|
|
51
|
+
name: 'project-path',
|
|
52
|
+
alias: 'i',
|
|
53
|
+
description:
|
|
54
|
+
'{bold ' +
|
|
55
|
+
i18n.__('constantsOptional') +
|
|
56
|
+
'}: ' +
|
|
57
|
+
i18n.__('constantsProjectPath')
|
|
58
|
+
},
|
|
50
59
|
{
|
|
51
60
|
name: 'timeout',
|
|
52
61
|
alias: 't',
|
|
@@ -146,6 +155,19 @@ const scanOptionDefinitions = [
|
|
|
146
155
|
name: 'debug',
|
|
147
156
|
alias: 'd',
|
|
148
157
|
type: Boolean
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: 'experimental',
|
|
161
|
+
alias: 'e',
|
|
162
|
+
type: Boolean
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: 'application-name',
|
|
166
|
+
description:
|
|
167
|
+
'{bold ' +
|
|
168
|
+
i18n.__('constantsOptional') +
|
|
169
|
+
'}: ' +
|
|
170
|
+
i18n.__('constantsApplicationName')
|
|
149
171
|
}
|
|
150
172
|
]
|
|
151
173
|
|
|
@@ -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) => {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export enum StatusType {
|
|
2
|
+
FAILED = 'failed',
|
|
3
|
+
SUCCESS = 'success'
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export enum EventType {
|
|
7
|
+
START = 'start_command_session',
|
|
8
|
+
END = 'end_command_session'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type LambdaOptions = {
|
|
12
|
+
functionName?: string
|
|
13
|
+
listFunctions?: boolean
|
|
14
|
+
region?: string
|
|
15
|
+
endpointUrl?: string
|
|
16
|
+
profile?: string
|
|
17
|
+
help?: boolean
|
|
18
|
+
verbose?: boolean
|
|
19
|
+
jsonOutput?: boolean
|
|
20
|
+
_unknown?: string[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type ScanFunctionData = {
|
|
24
|
+
functionArn: string
|
|
25
|
+
scanId: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type AnalyticsOption = {
|
|
29
|
+
sessionId: string
|
|
30
|
+
eventType: EventType
|
|
31
|
+
arguments?: LambdaOptions
|
|
32
|
+
scanFunctionData?: ScanFunctionData
|
|
33
|
+
status?: StatusType
|
|
34
|
+
errorMsg?: string
|
|
35
|
+
}
|
package/src/lambda/utils.ts
CHANGED
|
@@ -19,13 +19,8 @@ class PrintVulnerability {
|
|
|
19
19
|
whatHappened: string
|
|
20
20
|
|
|
21
21
|
constructor(index: number, vulnerability: any, group?: any[]) {
|
|
22
|
-
const {
|
|
23
|
-
|
|
24
|
-
title,
|
|
25
|
-
description,
|
|
26
|
-
remediation,
|
|
27
|
-
categoryText
|
|
28
|
-
} = vulnerability
|
|
22
|
+
const { severityText, title, description, remediation, categoryText } =
|
|
23
|
+
vulnerability
|
|
29
24
|
|
|
30
25
|
this.group = group
|
|
31
26
|
this.vulnerability = vulnerability
|