@contrast/contrast 2.0.1 → 2.0.2-beta.1
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/report/reportingFeature.js +7 -0
- package/dist/cliConstants.js +9 -8
- package/dist/commands/audit/processAudit.js +0 -2
- package/dist/commands/github/fingerprintConfig.js +2 -1
- package/dist/commands/github/processFingerprint.js +17 -7
- package/dist/commands/github/projectGroup.js +110 -30
- package/dist/commands/github/repoServices.js +42 -4
- package/dist/common/HTTPClient.js +37 -16
- package/dist/common/baseRequest.js +74 -0
- package/dist/constants/constants.js +1 -1
- package/dist/scaAnalysis/common/auditReport.js +8 -1
- package/dist/scaAnalysis/common/scaServicesUpload.js +3 -1
- package/dist/scaAnalysis/go/goReadDepFile.js +5 -1
- package/dist/scaAnalysis/java/analysis.js +1 -1
- package/dist/scaAnalysis/java/javaBuildDepsParser.js +11 -1
- package/dist/scaAnalysis/legacy/legacyFlow.js +0 -6
- package/dist/scaAnalysis/processServicesFlow.js +38 -17
- package/dist/scaAnalysis/repoMode/mavenParser.js +95 -53
- package/dist/scaAnalysis/scaAnalysis.js +4 -8
- package/dist/scan/autoDetection.js +12 -5
- package/dist/scan/fileUtils.js +33 -19
- package/dist/utils/paramsUtil/paramHandler.js +11 -2
- package/dist/utils/validationCheck.js +5 -1
- package/package.json +7 -3
- package/src/audit/report/reportingFeature.ts +7 -0
- package/src/cliConstants.js +9 -8
- package/src/commands/audit/processAudit.js +0 -2
- package/src/commands/github/fingerprintConfig.js +2 -2
- package/src/commands/github/processFingerprint.js +21 -11
- package/src/commands/github/projectGroup.js +131 -35
- package/src/commands/github/repoServices.js +46 -4
- package/src/common/HTTPClient.js +46 -17
- package/src/common/baseRequest.ts +83 -0
- package/src/constants/constants.js +1 -1
- package/src/scaAnalysis/common/auditReport.js +8 -1
- package/src/scaAnalysis/common/scaServicesUpload.js +5 -1
- package/src/scaAnalysis/go/goReadDepFile.js +5 -1
- package/src/scaAnalysis/java/analysis.js +1 -1
- package/src/scaAnalysis/java/javaBuildDepsParser.js +17 -1
- package/src/scaAnalysis/legacy/legacyFlow.js +0 -5
- package/src/scaAnalysis/processServicesFlow.js +82 -24
- package/src/scaAnalysis/repoMode/mavenParser.js +112 -62
- package/src/scaAnalysis/scaAnalysis.js +9 -8
- package/src/scan/autoDetection.js +12 -5
- package/src/scan/fileUtils.js +33 -19
- package/src/utils/paramsUtil/paramHandler.js +16 -2
- package/src/utils/validationCheck.js +6 -1
- package/dist/utils/settingsHelper.js +0 -14
- package/src/utils/settingsHelper.js +0 -16
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { HttpsProxyAgent } from 'hpagent'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import got, { Options } from 'got'
|
|
4
|
+
import { Agents, HTTPSOptions } from 'got/dist/source/core'
|
|
5
|
+
|
|
6
|
+
export function gotInstance(config: any) {
|
|
7
|
+
return got.extend({ retry: { limit: 0 }, ...buildBaseRequestOptions(config) })
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function buildBaseRequestOptions(config: any) {
|
|
11
|
+
const { apiKey, authorization } = config
|
|
12
|
+
const rejectUnauthorized = !config.certSelfSigned
|
|
13
|
+
|
|
14
|
+
const superApiKey = config.superApiKey
|
|
15
|
+
const superAuthToken = config.superAuthorization
|
|
16
|
+
|
|
17
|
+
const requestOptions = {
|
|
18
|
+
responseType: 'json',
|
|
19
|
+
forever: true,
|
|
20
|
+
uri: config.host,
|
|
21
|
+
followRedirect: false,
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
24
|
+
Authorization: authorization,
|
|
25
|
+
'API-Key': apiKey,
|
|
26
|
+
SuperAuthorization: superAuthToken,
|
|
27
|
+
'Super-API-Key': superApiKey,
|
|
28
|
+
'User-Agent': 'contrast-cli-v2'
|
|
29
|
+
},
|
|
30
|
+
agent: getAgent(config)
|
|
31
|
+
} as Options
|
|
32
|
+
|
|
33
|
+
requestOptions.https = {
|
|
34
|
+
rejectUnauthorized: rejectUnauthorized
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
maybeAddCertsToRequest(config, requestOptions.https)
|
|
38
|
+
return requestOptions
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getAgent(config: any) {
|
|
42
|
+
return config.proxy
|
|
43
|
+
? (new HttpsProxyAgent({ proxy: config.proxy }) as Agents)
|
|
44
|
+
: false
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function maybeAddCertsToRequest(config: any, https: HTTPSOptions) {
|
|
48
|
+
// cacert
|
|
49
|
+
const caCertFilePath = config.cacert
|
|
50
|
+
if (caCertFilePath) {
|
|
51
|
+
try {
|
|
52
|
+
https.certificateAuthority = fs.readFileSync(caCertFilePath)
|
|
53
|
+
} catch (error: any) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Unable to read CA from ${caCertFilePath}, msg: ${error.message}`
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// cert
|
|
61
|
+
const certPath = config.cert
|
|
62
|
+
if (certPath) {
|
|
63
|
+
try {
|
|
64
|
+
https.certificate = fs.readFileSync(certPath)
|
|
65
|
+
} catch (error: any) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
`Unable to read Certificate PEM file from config option contrast.api.certificate.cert_file='${certPath}', msg: ${error.message}`
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// key
|
|
73
|
+
const keyPath = config.key
|
|
74
|
+
if (keyPath) {
|
|
75
|
+
try {
|
|
76
|
+
https.key = fs.readFileSync(keyPath)
|
|
77
|
+
} catch (error: any) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`Unable to read Key PEM file from config option contrast.api.certificate.key_file='${keyPath}', msg: ${error.message}`
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -4,13 +4,20 @@ const {
|
|
|
4
4
|
} = require('../../audit/report/commonReportingFunctions')
|
|
5
5
|
const common = require('../../common/fail')
|
|
6
6
|
const { printFormattedOutputSca } = require('./commonReportingFunctionsSca')
|
|
7
|
+
const { auditSave } = require('../../audit/save')
|
|
7
8
|
|
|
8
|
-
const processAuditReport = (config, reportModelList) => {
|
|
9
|
+
const processAuditReport = async (config, reportModelList, reportId) => {
|
|
9
10
|
let severityCounts = {}
|
|
10
11
|
if (reportModelList !== undefined) {
|
|
11
12
|
severityCounts = formatScaServicesReport(config, reportModelList)
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
if (config.save !== undefined) {
|
|
16
|
+
await auditSave(config, reportId)
|
|
17
|
+
} else {
|
|
18
|
+
console.log('Use contrast audit --save to generate an SBOM')
|
|
19
|
+
}
|
|
20
|
+
|
|
14
21
|
if (config.fail) {
|
|
15
22
|
common.processFail(config, severityCounts)
|
|
16
23
|
}
|
|
@@ -14,8 +14,12 @@ const scaTreeUpload = async (analysis, config, reportSpinner) => {
|
|
|
14
14
|
config.language = config.language === 'JAVASCRIPT' ? 'NODE' : config.language
|
|
15
15
|
const startTime = performance.now()
|
|
16
16
|
const timeout = commonApi.getTimeout(config)
|
|
17
|
+
|
|
18
|
+
const doINeedParent = config.repositoryId && config.language === 'JAVA'
|
|
19
|
+
|
|
17
20
|
const requestBody = {
|
|
18
|
-
|
|
21
|
+
parentPom: doINeedParent ? analysis.parentPom : null,
|
|
22
|
+
dependencyTree: doINeedParent ? analysis.dependencyTree : analysis,
|
|
19
23
|
organizationId: config.organizationId,
|
|
20
24
|
language: config.language,
|
|
21
25
|
tool: {
|
|
@@ -8,7 +8,10 @@ const getGoDependencies = config => {
|
|
|
8
8
|
try {
|
|
9
9
|
// A sample of this output can be found
|
|
10
10
|
// in the go test folder data/goModGraphResults.text
|
|
11
|
-
cmdStdout = child_process.execSync('go mod graph', {
|
|
11
|
+
cmdStdout = child_process.execSync('go mod graph', {
|
|
12
|
+
cwd: cwd,
|
|
13
|
+
maxBuffer: 50 * 1024 * 1024
|
|
14
|
+
})
|
|
12
15
|
|
|
13
16
|
return cmdStdout.toString()
|
|
14
17
|
} catch (err) {
|
|
@@ -22,6 +25,7 @@ const getGoDependencies = config => {
|
|
|
22
25
|
// throw new Error(
|
|
23
26
|
// i18n.__('goReadProjectFile', cwd, `${err.message ? err.message : ''}`)
|
|
24
27
|
// )
|
|
28
|
+
process.exit(1)
|
|
25
29
|
}
|
|
26
30
|
}
|
|
27
31
|
|
|
@@ -30,7 +30,7 @@ const determineProjectTypeAndCwd = (files, config) => {
|
|
|
30
30
|
|
|
31
31
|
const buildMaven = (config, projectData, timeout) => {
|
|
32
32
|
let command = 'mvn'
|
|
33
|
-
let args = ['dependency:tree', '-B']
|
|
33
|
+
let args = ['dependency:tree', '-B', '-Dscope=runtime']
|
|
34
34
|
if (config.mavenSettingsPath) {
|
|
35
35
|
args.push('-s')
|
|
36
36
|
args.push(config.mavenSettingsPath)
|
|
@@ -140,7 +140,7 @@ const computeRelationToLastElement = element => {
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
const stripElement = element => {
|
|
143
|
-
|
|
143
|
+
const initialStrippedElement = element
|
|
144
144
|
.replace(/[|]/g, '')
|
|
145
145
|
.replace('+---', '')
|
|
146
146
|
.replace('\\---', '')
|
|
@@ -148,6 +148,22 @@ const stripElement = element => {
|
|
|
148
148
|
.replace('(c)', '')
|
|
149
149
|
.replace('->', '@')
|
|
150
150
|
.replace('(*)', '')
|
|
151
|
+
|
|
152
|
+
//work out Gradle resolved versioning e.g. org.slf4j:slf4j-api:1.7.25 -> 1.7.22
|
|
153
|
+
//take 1.7.22
|
|
154
|
+
const splitElements = initialStrippedElement.split(':')
|
|
155
|
+
if (
|
|
156
|
+
splitElements[2] !== undefined &&
|
|
157
|
+
splitElements[2] !== null &&
|
|
158
|
+
splitElements[2].includes('@')
|
|
159
|
+
) {
|
|
160
|
+
const splitVersions = splitElements[2].split('@')
|
|
161
|
+
return initialStrippedElement
|
|
162
|
+
.replace(':' + splitVersions[0], '')
|
|
163
|
+
.replace('@', ':')
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return initialStrippedElement
|
|
151
167
|
}
|
|
152
168
|
|
|
153
169
|
const checkVersion = element => {
|
|
@@ -32,11 +32,6 @@ const legacyFlow = async (config, messageToSend) => {
|
|
|
32
32
|
succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'))
|
|
33
33
|
|
|
34
34
|
await vulnerabilityReportV2(config, snapshotResponse.id)
|
|
35
|
-
if (config.save !== undefined) {
|
|
36
|
-
await auditSave(config)
|
|
37
|
-
} else {
|
|
38
|
-
console.log('\nUse contrast audit --save to generate an SBOM')
|
|
39
|
-
}
|
|
40
35
|
const endTime = performance.now() - startTime
|
|
41
36
|
const scanDurationMs = endTime - startTime
|
|
42
37
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const projectConfig = require('../commands/github/projectGroup')
|
|
2
|
+
const repoService = require('../commands/github/repoServices')
|
|
2
3
|
const scaServicesUpload = require('../scaAnalysis/common/scaServicesUpload')
|
|
3
4
|
|
|
4
|
-
const
|
|
5
|
+
const dealWithNoProjectId = async (analysis, config, reportSpinner) => {
|
|
5
6
|
await projectConfig.registerNewProjectGroup(config)
|
|
6
7
|
let projectId = await projectConfig.getProjectIdByOrg(config)
|
|
7
8
|
await projectConfig.registerProjectIdOnCliServices(config, projectId)
|
|
@@ -10,29 +11,83 @@ const trackProcess = async (analysis, config, reportSpinner) => {
|
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
const repoProcess = async (analysis, config, reportSpinner) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
if (config.debug || config.verbose) {
|
|
15
|
+
console.log('in repository process')
|
|
16
|
+
console.log('repository id: ', config.repositoryId)
|
|
17
|
+
}
|
|
18
|
+
if (config.repositoryId === '') {
|
|
19
|
+
console.log('Failed to retrieve Repository Id')
|
|
20
|
+
process.exit(1)
|
|
16
21
|
}
|
|
17
|
-
await projectConfig.registerProjectIdOnCliServices(config, repoInfo.projectId)
|
|
18
|
-
return repoInfo
|
|
19
|
-
}
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
let repoInfo = await repoService.retrieveProjectInfoViaRepoId(config)
|
|
24
|
+
|
|
25
|
+
repoInfo = repoInfo.find(
|
|
26
|
+
element =>
|
|
27
|
+
config.fileName === element.path &&
|
|
28
|
+
config.fileName === element.name &&
|
|
29
|
+
config.projectGroupId === element.projectGroupId
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
// console.log('repoInfo', repoInfo)
|
|
33
|
+
|
|
34
|
+
// if(repoInfo !== undefined) {
|
|
35
|
+
// console.log('re-register / register first time')
|
|
36
|
+
// const language = repoInfo.language === 'JAVASCRIPT' ? 'NODE' : repoInfo.language
|
|
37
|
+
// const additionalData = {
|
|
38
|
+
// projectGroupId: repoInfo.projectGroupId,
|
|
39
|
+
// projectGroupName: repoInfo.name,
|
|
40
|
+
// projectLanguage: language,
|
|
41
|
+
// projectType: 'REPOSITORY'
|
|
42
|
+
// }
|
|
43
|
+
//
|
|
44
|
+
// // check project exists in sca / register (just in case, it failed in the past)
|
|
45
|
+
// await projectConfig.registerProjectIdOnCliServices(
|
|
46
|
+
// config,
|
|
47
|
+
// repoInfo.projectId,
|
|
48
|
+
// additionalData
|
|
49
|
+
// )
|
|
24
50
|
// }
|
|
25
|
-
if (config.track) {
|
|
26
|
-
return trackProcess(analysis, config, reportSpinner)
|
|
27
|
-
}
|
|
28
51
|
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
52
|
+
if (
|
|
53
|
+
config.projectGroupId &&
|
|
54
|
+
!repoInfo?.projectId &&
|
|
55
|
+
(repoInfo === undefined || repoInfo.length === 0)
|
|
56
|
+
) {
|
|
57
|
+
console.log(
|
|
58
|
+
'*** has projectGroupId, no projectId and repo has no project found that matches'
|
|
59
|
+
)
|
|
60
|
+
repoInfo = await projectConfig.registerProjectWithGroupProjectId(config)
|
|
61
|
+
console.log('new registered group', repoInfo)
|
|
62
|
+
const language =
|
|
63
|
+
repoInfo.language === 'JAVASCRIPT' ? 'NODE' : repoInfo.language
|
|
64
|
+
|
|
65
|
+
// const additionalData = {
|
|
66
|
+
// projectGroupId: repoInfo.projectGroupId,
|
|
67
|
+
// projectGroupName: repoInfo.name,
|
|
68
|
+
// projectLanguage: language,
|
|
69
|
+
// projectType: 'REPOSITORY'
|
|
70
|
+
// }
|
|
71
|
+
|
|
72
|
+
await projectConfig.registerProjectIdOnCliServices(
|
|
32
73
|
config,
|
|
33
|
-
|
|
74
|
+
repoInfo.projectId
|
|
34
75
|
)
|
|
35
76
|
}
|
|
77
|
+
config.projectId = repoInfo.projectId
|
|
78
|
+
return await scaServicesUpload.scaTreeUpload(analysis, config, reportSpinner)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const trackProcess = async (analysis, config, reportSpinner) => {
|
|
82
|
+
let projectId = await projectConfig.getProjectIdByOrg(config)
|
|
83
|
+
|
|
84
|
+
if (projectId === '') {
|
|
85
|
+
return dealWithNoProjectId(analysis, config, reportSpinner)
|
|
86
|
+
}
|
|
87
|
+
config.projectId = projectId
|
|
88
|
+
// we can always register just in case but normally we exit when
|
|
89
|
+
await projectConfig.registerProjectIdOnCliServices(config, projectId)
|
|
90
|
+
return await scaServicesUpload.scaTreeUpload(analysis, config, reportSpinner)
|
|
36
91
|
}
|
|
37
92
|
|
|
38
93
|
const processUpload = async (analysis, config, reportSpinner) => {
|
|
@@ -40,15 +95,17 @@ const processUpload = async (analysis, config, reportSpinner) => {
|
|
|
40
95
|
// if cli tracked but no projectId -> registerNewProjectGroup THEN scaTreeUpload
|
|
41
96
|
// if cli not tracked and no projectID -> noProjectUpload
|
|
42
97
|
// if cli not tracked and projectID -> scaTreeUpload}
|
|
43
|
-
let projectId = await projectConfig.getProjectIdByOrg(config)
|
|
44
98
|
|
|
45
|
-
if (
|
|
46
|
-
return
|
|
99
|
+
if (config.repositoryId) {
|
|
100
|
+
return repoProcess(analysis, config, reportSpinner)
|
|
47
101
|
}
|
|
48
102
|
|
|
49
|
-
if (
|
|
50
|
-
config
|
|
51
|
-
|
|
103
|
+
if (config.track) {
|
|
104
|
+
return trackProcess(analysis, config, reportSpinner)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!config.track) {
|
|
108
|
+
return await scaServicesUpload.noProjectUpload(
|
|
52
109
|
analysis,
|
|
53
110
|
config,
|
|
54
111
|
reportSpinner
|
|
@@ -57,5 +114,6 @@ const processUpload = async (analysis, config, reportSpinner) => {
|
|
|
57
114
|
}
|
|
58
115
|
|
|
59
116
|
module.exports = {
|
|
60
|
-
processUpload
|
|
117
|
+
processUpload,
|
|
118
|
+
repoProcess
|
|
61
119
|
}
|
|
@@ -1,89 +1,139 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
|
-
const
|
|
2
|
+
const { XMLParser } = require('fast-xml-parser')
|
|
3
3
|
|
|
4
4
|
const readPomFile = project => {
|
|
5
5
|
const mavenFilePath = project.cwd + '/pom.xml'
|
|
6
6
|
const projectFile = fs.readFileSync(mavenFilePath)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
const parser = new XMLParser()
|
|
8
|
+
return parser.parse(projectFile)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const parsePomFile = jsonPomFile => {
|
|
12
|
+
console.log(JSON.stringify(jsonPomFile))
|
|
13
|
+
let dependencyTree = {}
|
|
14
|
+
let dependencies = []
|
|
15
|
+
let dependencyManagement = []
|
|
16
|
+
|
|
17
|
+
if (jsonPomFile.project && jsonPomFile.project.dependencies) {
|
|
18
|
+
dependencies = jsonPomFile.project.dependencies.dependency
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (jsonPomFile.project && jsonPomFile.project.dependencyManagement) {
|
|
22
|
+
dependencyManagement =
|
|
23
|
+
jsonPomFile.project.dependencyManagement.dependencies.dependency
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//merge dependencies with dependencyManagement deps
|
|
27
|
+
//filter out any that don't appear in both by groupId and artifactId
|
|
28
|
+
const mergedAndFilteredDeps = dependencies.map(obj1 => {
|
|
29
|
+
const obj2 = dependencyManagement.find(
|
|
30
|
+
obj2 =>
|
|
31
|
+
obj2.groupId === obj1.groupId && obj2.artifactId === obj1.artifactId
|
|
32
|
+
)
|
|
33
|
+
return obj2 ? { ...obj1, ...obj2 } : obj1
|
|
14
34
|
})
|
|
15
|
-
|
|
35
|
+
|
|
36
|
+
buildDependencies(mergedAndFilteredDeps, dependencyTree, jsonPomFile)
|
|
37
|
+
return {
|
|
38
|
+
parentPom: getParentDependency(jsonPomFile),
|
|
39
|
+
dependencyTree
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const getParentDependency = jsonPomFile => {
|
|
44
|
+
if (jsonPomFile.project && jsonPomFile.project.parent) {
|
|
45
|
+
return buildParent(jsonPomFile.project.parent)
|
|
46
|
+
} else {
|
|
47
|
+
return undefined
|
|
48
|
+
}
|
|
16
49
|
}
|
|
17
50
|
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
51
|
+
const buildParent = parent => {
|
|
52
|
+
return {
|
|
53
|
+
group: parent.groupId,
|
|
54
|
+
name: parent.artifactId,
|
|
55
|
+
version: parent.version
|
|
56
|
+
}
|
|
57
|
+
}
|
|
23
58
|
|
|
24
|
-
|
|
25
|
-
|
|
59
|
+
const getVersionFromParent = (parentObj, dependencyWithoutVersion) => {
|
|
60
|
+
const { groupId, version } = parentObj
|
|
61
|
+
if (groupId === dependencyWithoutVersion.groupId) {
|
|
62
|
+
return version
|
|
26
63
|
} else {
|
|
27
64
|
return null
|
|
28
65
|
}
|
|
29
66
|
}
|
|
30
67
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
let dependencyObject = dependencies[x]
|
|
42
|
-
if (!dependencyObject.hasOwnProperty('version')) {
|
|
43
|
-
parsedVersion = getVersion(jsonPomFile, dependencyObject)
|
|
44
|
-
} else {
|
|
45
|
-
dependencyObject.version[0].includes('${versions.')
|
|
46
|
-
? (parsedVersion = getFromVersionsTag(
|
|
47
|
-
dependencyObject.artifactId[0],
|
|
48
|
-
dependencyObject.version[0],
|
|
49
|
-
jsonPomFile
|
|
50
|
-
))
|
|
51
|
-
: (parsedVersion = dependencyObject.version[0])
|
|
68
|
+
const getVersionFromProperties = (properties, dep) => {
|
|
69
|
+
if (properties && dep.version.includes('${')) {
|
|
70
|
+
const currentDepVersionPlaceholder = dep.version
|
|
71
|
+
.replace('${', '')
|
|
72
|
+
.replace('}', '')
|
|
73
|
+
|
|
74
|
+
for (const prop in properties) {
|
|
75
|
+
if (prop === currentDepVersionPlaceholder) {
|
|
76
|
+
return properties[prop]
|
|
77
|
+
}
|
|
52
78
|
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
53
81
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
version
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
82
|
+
const buildDependencies = (dependencies, dependencyTree, jsonPomFile) => {
|
|
83
|
+
const parent = getParentDependency(jsonPomFile)
|
|
84
|
+
for (const dep of dependencies) {
|
|
85
|
+
//sometimes versions are parsed as numbers, convert to string
|
|
86
|
+
const versionAsString = dep.version ? dep.version.toString() : dep.version
|
|
87
|
+
if (versionAsString && !versionAsString.includes('${')) {
|
|
88
|
+
const depName = dep.groupId + '/' + dep.artifactId + '@' + versionAsString
|
|
89
|
+
dependencyTree[depName] = buildDep(dep, dep.version)
|
|
90
|
+
} else if (
|
|
91
|
+
jsonPomFile.project.properties &&
|
|
92
|
+
dep.version &&
|
|
93
|
+
dep.version.includes('${')
|
|
94
|
+
) {
|
|
95
|
+
searchAndBuildFromProperties(jsonPomFile, dep, dependencyTree)
|
|
96
|
+
} else if (!dep.version) {
|
|
97
|
+
if (parent && parent.version) {
|
|
98
|
+
//get version where group matches from parent tag
|
|
99
|
+
const { parent } = jsonPomFile.project
|
|
100
|
+
const parsedVersion = getVersionFromParent(parent, dep)
|
|
101
|
+
const depName = dep.groupId + '/' + dep.artifactId + '@' + parsedVersion
|
|
102
|
+
dependencyTree[depName] = buildDep(dep, parsedVersion)
|
|
103
|
+
}
|
|
68
104
|
}
|
|
69
|
-
dependencyTree[depName] = parsedDependency
|
|
70
105
|
}
|
|
71
|
-
return dependencyTree
|
|
72
106
|
}
|
|
73
107
|
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
108
|
+
const searchAndBuildFromProperties = (jsonPomFile, dep, dependencyTree) => {
|
|
109
|
+
//get version from properties tag
|
|
110
|
+
const { properties } = jsonPomFile.project
|
|
111
|
+
let versionFromProperties = getVersionFromProperties(properties, dep)
|
|
112
|
+
|
|
113
|
+
if (versionFromProperties) {
|
|
114
|
+
versionFromProperties = versionFromProperties.toString()
|
|
115
|
+
const depName =
|
|
116
|
+
dep.groupId + '/' + dep.artifactId + '@' + versionFromProperties
|
|
117
|
+
dependencyTree[depName] = buildDep(dep, versionFromProperties)
|
|
79
118
|
} else {
|
|
80
|
-
|
|
119
|
+
const depName = dep.groupId + '/' + dep.artifactId + '@' + null
|
|
120
|
+
dependencyTree[depName] = buildDep(dep, null)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const buildDep = (dep, version) => {
|
|
125
|
+
return {
|
|
126
|
+
name: dep.artifactId,
|
|
127
|
+
group: dep.groupId,
|
|
128
|
+
version: version,
|
|
129
|
+
directDependency: true,
|
|
130
|
+
productionDependency: true,
|
|
131
|
+
dependencies: []
|
|
81
132
|
}
|
|
82
133
|
}
|
|
83
134
|
|
|
84
135
|
module.exports = {
|
|
85
136
|
readPomFile,
|
|
86
|
-
|
|
87
|
-
parsePomFile
|
|
88
|
-
getFromVersionsTag
|
|
137
|
+
getVersionFromParent,
|
|
138
|
+
parsePomFile
|
|
89
139
|
}
|
|
@@ -10,7 +10,6 @@ const autoDetection = require('../scan/autoDetection')
|
|
|
10
10
|
const rootFile = require('../audit/languageAnalysisEngine/getProjectRootFilenames')
|
|
11
11
|
const path = require('path')
|
|
12
12
|
const i18n = require('i18n')
|
|
13
|
-
const auditSave = require('../audit/save')
|
|
14
13
|
const { auditUsageGuide } = require('../commands/audit/help')
|
|
15
14
|
const repoMode = require('./repoMode')
|
|
16
15
|
const { dotNetAnalysis } = require('./dotnet')
|
|
@@ -37,6 +36,8 @@ const processSca = async config => {
|
|
|
37
36
|
process.exit(0)
|
|
38
37
|
}
|
|
39
38
|
|
|
39
|
+
config.repo = config.repositoryId !== undefined
|
|
40
|
+
|
|
40
41
|
const projectStats = await rootFile.getProjectStats(config.file)
|
|
41
42
|
let pathWithFile = projectStats.isFile()
|
|
42
43
|
|
|
@@ -46,7 +47,7 @@ const processSca = async config => {
|
|
|
46
47
|
: config.file
|
|
47
48
|
|
|
48
49
|
filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config.file)
|
|
49
|
-
|
|
50
|
+
filesFound = await autoDetection.detectPackageManager(filesFound)
|
|
50
51
|
autoDetection.dealWithMultiJava(filesFound)
|
|
51
52
|
|
|
52
53
|
if (filesFound.length > 1 && pathWithFile) {
|
|
@@ -59,6 +60,7 @@ const processSca = async config => {
|
|
|
59
60
|
//check we have the language and call the right analyser
|
|
60
61
|
let messageToSend = undefined
|
|
61
62
|
if (filesFound.length === 1) {
|
|
63
|
+
config.packageManager = filesFound[0]?.packageManager
|
|
62
64
|
switch (Object.keys(filesFound[0])[0]) {
|
|
63
65
|
case JAVA:
|
|
64
66
|
config.language = JAVA
|
|
@@ -131,12 +133,11 @@ const processSca = async config => {
|
|
|
131
133
|
const reportModelLibraryList = convertGenericToTypedReportModelSca(
|
|
132
134
|
reportResponse.reportArray
|
|
133
135
|
)
|
|
134
|
-
auditReport.processAuditReport(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
136
|
+
await auditReport.processAuditReport(
|
|
137
|
+
config,
|
|
138
|
+
reportModelLibraryList,
|
|
139
|
+
reportResponse.reportId
|
|
140
|
+
)
|
|
140
141
|
|
|
141
142
|
succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'))
|
|
142
143
|
|
|
@@ -9,11 +9,14 @@ const autoDetectFingerprintInfo = async (filePath, depth, config) => {
|
|
|
9
9
|
let count = 0
|
|
10
10
|
complexObj.forEach(i => {
|
|
11
11
|
count++
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
if (!i.includes('package.json')) {
|
|
13
|
+
result.push({
|
|
14
|
+
filePath: i,
|
|
15
|
+
id: count.toString(),
|
|
16
|
+
repositoryId: config.repositoryId,
|
|
17
|
+
projectGroupId: config.projectGroupId
|
|
18
|
+
})
|
|
19
|
+
}
|
|
17
20
|
})
|
|
18
21
|
|
|
19
22
|
return result
|
|
@@ -43,15 +46,19 @@ const detectPackageManager = async array => {
|
|
|
43
46
|
}
|
|
44
47
|
if (i.filePath.includes('Pipfile')) {
|
|
45
48
|
i['language'] = PYTHON
|
|
49
|
+
i['packageManager'] = 'PYPI'
|
|
46
50
|
}
|
|
47
51
|
if (i.filePath.includes('csproj')) {
|
|
48
52
|
i['language'] = DOTNET
|
|
53
|
+
i['packageManager'] = 'NUGET'
|
|
49
54
|
}
|
|
50
55
|
if (i.filePath.includes('Gemfile')) {
|
|
51
56
|
i['language'] = RUBY
|
|
57
|
+
i['packageManager'] = 'RUBYGEMS'
|
|
52
58
|
}
|
|
53
59
|
if (i.filePath.includes('go.mod')) {
|
|
54
60
|
i['language'] = GO
|
|
61
|
+
i['packageManager'] = 'PKG'
|
|
55
62
|
}
|
|
56
63
|
})
|
|
57
64
|
return array
|