@contrast/contrast 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/autodetection/autoDetectLanguage.js +3 -3
- package/dist/audit/catalogueApplication/catalogueApplication.js +23 -5
- package/dist/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +5 -5
- package/dist/audit/languageAnalysisEngine/getProjectRootFilenames.js +9 -9
- package/dist/audit/languageAnalysisEngine/index.js +2 -2
- package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +5 -28
- package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +11 -4
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +39 -13
- package/dist/audit/languageAnalysisEngine/report/models/reportListModel.js +2 -1
- package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +3 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +35 -14
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +3 -3
- package/dist/audit/save.js +29 -0
- package/dist/commands/audit/auditController.js +21 -5
- package/dist/commands/audit/help.js +24 -1
- package/dist/commands/audit/processAudit.js +7 -1
- package/dist/commands/audit/saveFile.js +7 -3
- package/dist/commands/scan/sca/scaAnalysis.js +31 -10
- package/dist/common/HTTPClient.js +6 -0
- package/dist/common/versionChecker.js +19 -4
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +12 -11
- package/dist/constants.js +9 -4
- package/dist/index.js +4 -3
- package/dist/sbom/generateSbom.js +4 -3
- package/dist/scaAnalysis/common/formatMessage.js +26 -5
- package/dist/scaAnalysis/common/treeUpload.js +0 -1
- package/dist/scaAnalysis/go/goReadDepFile.js +1 -3
- package/dist/scaAnalysis/java/analysis.js +5 -5
- package/dist/scaAnalysis/javascript/analysis.js +110 -0
- package/dist/scaAnalysis/javascript/index.js +41 -0
- package/dist/scaAnalysis/php/analysis.js +89 -0
- package/dist/scaAnalysis/php/index.js +10 -0
- package/dist/scaAnalysis/python/analysis.js +8 -7
- package/dist/scaAnalysis/ruby/analysis.js +8 -8
- package/dist/scaAnalysis/ruby/index.js +2 -2
- package/dist/scan/autoDetection.js +4 -4
- package/dist/scan/fileUtils.js +13 -2
- package/dist/utils/filterProjectPath.js +7 -2
- package/package.json +3 -3
- package/src/audit/autodetection/autoDetectLanguage.ts +3 -3
- package/src/audit/catalogueApplication/catalogueApplication.js +28 -6
- package/src/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +5 -5
- package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +11 -11
- package/src/audit/languageAnalysisEngine/index.js +2 -2
- package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +4 -32
- package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +20 -19
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +67 -17
- package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +4 -1
- package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +4 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +49 -17
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +1 -1
- package/src/audit/save.js +32 -0
- package/src/commands/audit/auditController.ts +22 -13
- package/src/commands/audit/help.ts +24 -1
- package/src/commands/audit/processAudit.ts +6 -3
- package/src/commands/audit/saveFile.ts +5 -1
- package/src/commands/scan/sca/scaAnalysis.js +53 -22
- package/src/common/HTTPClient.js +7 -0
- package/src/common/versionChecker.ts +23 -4
- package/src/constants/constants.js +1 -1
- package/src/constants/locales.js +12 -11
- package/src/constants.js +9 -4
- package/src/index.ts +5 -3
- package/src/sbom/generateSbom.ts +1 -1
- package/src/scaAnalysis/common/formatMessage.js +27 -5
- package/src/scaAnalysis/common/treeUpload.js +0 -1
- package/src/scaAnalysis/go/goReadDepFile.js +1 -3
- package/src/scaAnalysis/java/analysis.js +5 -5
- package/src/scaAnalysis/javascript/analysis.js +127 -0
- package/src/scaAnalysis/javascript/index.js +56 -0
- package/src/scaAnalysis/php/analysis.js +98 -0
- package/src/scaAnalysis/php/index.js +11 -0
- package/src/scaAnalysis/python/analysis.js +8 -7
- package/src/scaAnalysis/ruby/analysis.js +8 -8
- package/src/scaAnalysis/ruby/index.js +2 -2
- package/src/scan/autoDetection.js +4 -4
- package/src/scan/fileUtils.js +13 -2
- package/src/utils/filterProjectPath.js +6 -2
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,12 +137,12 @@ 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:
|
|
@@ -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.',
|
|
@@ -393,13 +393,13 @@ const en_locales = () => {
|
|
|
393
393
|
auditOptionsIgnoreDevDependenciesDescription: 'ignores DevDependencies',
|
|
394
394
|
auditOptionsSave: '-s, --save',
|
|
395
395
|
auditOptionsSaveDescription:
|
|
396
|
-
'saves the output in specified format
|
|
396
|
+
'saves the output in specified format, options: sbom',
|
|
397
397
|
scanNotCompleted:
|
|
398
398
|
'Scan not completed. Check for framework and language support here: %s',
|
|
399
399
|
auditNotCompleted: 'audit not completed. Please try again',
|
|
400
|
-
scanNoVulnerabilitiesFound: '
|
|
400
|
+
scanNoVulnerabilitiesFound: '🎉 No vulnerabilities found.',
|
|
401
401
|
scanNoVulnerabilitiesFoundSecureCode: '👍 Your code looks secure.',
|
|
402
|
-
scanNoVulnerabilitiesFoundGoodWork: '
|
|
402
|
+
scanNoVulnerabilitiesFoundGoodWork: ' Keep up the good work.',
|
|
403
403
|
scanNoFiletypeSpecifiedForSave:
|
|
404
404
|
'Please specify file type to save results to, accepted value is SARIF',
|
|
405
405
|
auditSBOMSaveSuccess:
|
|
@@ -414,7 +414,8 @@ const en_locales = () => {
|
|
|
414
414
|
auditReportFail: 'Report Retrieval Failed, please try again',
|
|
415
415
|
auditReportSuccessMessage: 'Report successfully retrieved',
|
|
416
416
|
auditReportFailureMessage: 'Unable to generate library report',
|
|
417
|
-
auditSCAAnalysisBegins: 'Contrast SCA
|
|
417
|
+
auditSCAAnalysisBegins: 'Contrast SCA audit started',
|
|
418
|
+
auditSCAAnalysisComplete: 'Contrast SCA audit complete',
|
|
418
419
|
...lambda
|
|
419
420
|
}
|
|
420
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
|
|
package/src/sbom/generateSbom.ts
CHANGED
|
@@ -6,6 +6,21 @@ const createJavaTSMessage = javaTree => {
|
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
const createJavaScriptTSMessage = js => {
|
|
10
|
+
let message = {
|
|
11
|
+
node: {
|
|
12
|
+
packageJSON: js.packageJSON
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (js.yarn !== undefined) {
|
|
16
|
+
message.node.yarnLockFile = js.yarn.yarnLockFile
|
|
17
|
+
message.node.yarnVersion = js.yarn.yarnVersion
|
|
18
|
+
} else {
|
|
19
|
+
message.node.npmLockFile = js.npmLockFile
|
|
20
|
+
}
|
|
21
|
+
return message
|
|
22
|
+
}
|
|
23
|
+
|
|
9
24
|
const createGoTSMessage = goTree => {
|
|
10
25
|
return {
|
|
11
26
|
go: {
|
|
@@ -16,23 +31,30 @@ const createGoTSMessage = goTree => {
|
|
|
16
31
|
|
|
17
32
|
const createRubyTSMessage = rubyTree => {
|
|
18
33
|
return {
|
|
19
|
-
ruby:
|
|
20
|
-
rubyDependencyTrees: rubyTree
|
|
21
|
-
}
|
|
34
|
+
ruby: rubyTree
|
|
22
35
|
}
|
|
23
36
|
}
|
|
24
37
|
|
|
25
38
|
const createPythonTSMessage = pythonTree => {
|
|
26
39
|
return {
|
|
27
|
-
python:
|
|
28
|
-
|
|
40
|
+
python: pythonTree
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const createPhpTSMessage = phpTree => {
|
|
45
|
+
return {
|
|
46
|
+
php: {
|
|
47
|
+
composerJSON: phpTree.composerJSON,
|
|
48
|
+
lockFile: phpTree.lockFile
|
|
29
49
|
}
|
|
30
50
|
}
|
|
31
51
|
}
|
|
32
52
|
|
|
33
53
|
module.exports = {
|
|
54
|
+
createJavaScriptTSMessage,
|
|
34
55
|
createJavaTSMessage,
|
|
35
56
|
createGoTSMessage,
|
|
57
|
+
createPhpTSMessage,
|
|
36
58
|
createRubyTSMessage,
|
|
37
59
|
createPythonTSMessage
|
|
38
60
|
}
|
|
@@ -3,9 +3,7 @@ const i18n = require('i18n')
|
|
|
3
3
|
|
|
4
4
|
const getGoDependencies = config => {
|
|
5
5
|
let cmdStdout
|
|
6
|
-
let cwd = config.
|
|
7
|
-
? config.projectPath.replace('go.mod', '')
|
|
8
|
-
: process.cwd()
|
|
6
|
+
let cwd = config.file ? config.file.replace('go.mod', '') : process.cwd()
|
|
9
7
|
|
|
10
8
|
try {
|
|
11
9
|
// A sample of this output can be found
|
|
@@ -6,7 +6,7 @@ const fs = require('fs')
|
|
|
6
6
|
const MAVEN = 'maven'
|
|
7
7
|
const GRADLE = 'gradle'
|
|
8
8
|
|
|
9
|
-
const determineProjectTypeAndCwd = (files,
|
|
9
|
+
const determineProjectTypeAndCwd = (files, file) => {
|
|
10
10
|
const projectData = {}
|
|
11
11
|
|
|
12
12
|
if (files[0].includes('pom.xml')) {
|
|
@@ -16,9 +16,9 @@ const determineProjectTypeAndCwd = (files, projectPath) => {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
//clean up the path to be a folder not a file
|
|
19
|
-
projectData.cwd =
|
|
20
|
-
?
|
|
21
|
-
:
|
|
19
|
+
projectData.cwd = file
|
|
20
|
+
? file.replace('pom.xml', '').replace('build.gradle', '')
|
|
21
|
+
: file
|
|
22
22
|
|
|
23
23
|
return projectData
|
|
24
24
|
}
|
|
@@ -124,7 +124,7 @@ const getJavaBuildDeps = (config, files) => {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
try {
|
|
127
|
-
const projectData = determineProjectTypeAndCwd(files, config.
|
|
127
|
+
const projectData = determineProjectTypeAndCwd(files, config.file)
|
|
128
128
|
if (projectData.projectType === MAVEN) {
|
|
129
129
|
output.mvnDependancyTreeOutput = buildMaven(config, projectData, timeout)
|
|
130
130
|
} else if (projectData.projectType === GRADLE) {
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const yarnParser = require('@yarnpkg/lockfile')
|
|
3
|
+
const yaml = require('js-yaml')
|
|
4
|
+
const i18n = require('i18n')
|
|
5
|
+
const {
|
|
6
|
+
formatKey
|
|
7
|
+
} = require('../../audit/nodeAnalysisEngine/parseYarn2LockFileContents')
|
|
8
|
+
|
|
9
|
+
const readFile = async (config, languageFiles, nameOfFile) => {
|
|
10
|
+
const index = languageFiles.findIndex(v => v.includes(nameOfFile))
|
|
11
|
+
|
|
12
|
+
if (config.file) {
|
|
13
|
+
return fs.readFileSync(config.file.concat(languageFiles[index]), 'utf8')
|
|
14
|
+
} else {
|
|
15
|
+
console.log('could not find file')
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const readYarn = async (config, languageFiles, nameOfFile) => {
|
|
20
|
+
let yarn = {
|
|
21
|
+
yarnVersion: 1,
|
|
22
|
+
rawYarnLockFileContents: ''
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
let rawYarnLockFileContents = await readFile(
|
|
27
|
+
config,
|
|
28
|
+
languageFiles,
|
|
29
|
+
nameOfFile
|
|
30
|
+
)
|
|
31
|
+
yarn.rawYarnLockFileContents = rawYarnLockFileContents
|
|
32
|
+
|
|
33
|
+
if (
|
|
34
|
+
!yarn.rawYarnLockFileContents.includes('lockfile v1') ||
|
|
35
|
+
yarn.rawYarnLockFileContents.includes('__metadata')
|
|
36
|
+
) {
|
|
37
|
+
yarn.rawYarnLockFileContents = yaml.load(rawYarnLockFileContents)
|
|
38
|
+
yarn.yarnVersion = 2
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return yarn
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.log(i18n.__('nodeReadYarnLockFileError') + `${err.message}`)
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const parseNpmLockFile = async js => {
|
|
49
|
+
try {
|
|
50
|
+
js.npmLockFile = JSON.parse(js.rawLockFileContents)
|
|
51
|
+
if (js.npmLockFile && js.npmLockFile.lockfileVersion > 1) {
|
|
52
|
+
const listOfTopDep = Object.keys(js.npmLockFile.dependencies)
|
|
53
|
+
Object.entries(js.npmLockFile.dependencies).forEach(([objKey, value]) => {
|
|
54
|
+
if (value.requires) {
|
|
55
|
+
const listOfRequiresDep = Object.keys(value.requires)
|
|
56
|
+
listOfRequiresDep.forEach(dep => {
|
|
57
|
+
if (!listOfTopDep.includes(dep)) {
|
|
58
|
+
addDepToLockFile(js, value['requires'], dep)
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (value.dependencies) {
|
|
64
|
+
Object.entries(value.dependencies).forEach(
|
|
65
|
+
([objChildKey, childValue]) => {
|
|
66
|
+
if (childValue.requires) {
|
|
67
|
+
const listOfRequiresDep = Object.keys(childValue.requires)
|
|
68
|
+
listOfRequiresDep.forEach(dep => {
|
|
69
|
+
if (!listOfTopDep.includes(dep)) {
|
|
70
|
+
addDepToLockFile(js, childValue['requires'], dep)
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
return js.npmLockFile
|
|
79
|
+
} else {
|
|
80
|
+
return js.npmLockFile
|
|
81
|
+
}
|
|
82
|
+
} catch (err) {
|
|
83
|
+
console.log(i18n.__('NodeParseNPM') + `${err.message}`)
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const addDepToLockFile = (js, depObj, key) => {
|
|
89
|
+
return (js.npmLockFile.dependencies[key] = { version: depObj[key] })
|
|
90
|
+
}
|
|
91
|
+
const parseYarnLockFile = async js => {
|
|
92
|
+
try {
|
|
93
|
+
js.yarn.yarnLockFile = {}
|
|
94
|
+
if (js.yarn.yarnVersion === 1) {
|
|
95
|
+
js.yarn.yarnLockFile = yarnParser.parse(js.yarn.rawYarnLockFileContents)
|
|
96
|
+
delete js.yarn.rawYarnLockFileContents
|
|
97
|
+
return js
|
|
98
|
+
} else {
|
|
99
|
+
js.yarn.yarnLockFile['object'] = js.yarn.rawYarnLockFileContents
|
|
100
|
+
delete js.yarn.yarnLockFile['object'].__metadata
|
|
101
|
+
js.yarn.yarnLockFile['type'] = 'success'
|
|
102
|
+
|
|
103
|
+
Object.entries(js.yarn.rawYarnLockFileContents).forEach(
|
|
104
|
+
([key, value]) => {
|
|
105
|
+
const rawKeyNames = key.split(',')
|
|
106
|
+
const keyNames = formatKey(rawKeyNames)
|
|
107
|
+
|
|
108
|
+
keyNames.forEach(name => {
|
|
109
|
+
js.yarn.yarnLockFile.object[name] = value
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
)
|
|
113
|
+
return js
|
|
114
|
+
}
|
|
115
|
+
} catch (err) {
|
|
116
|
+
console.log(i18n.__('NodeParseYarn') + `${err.message}`)
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = {
|
|
122
|
+
readYarn,
|
|
123
|
+
parseYarnLockFile,
|
|
124
|
+
parseNpmLockFile,
|
|
125
|
+
readFile,
|
|
126
|
+
formatKey
|
|
127
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const analysis = require('./analysis')
|
|
2
|
+
const i18n = require('i18n')
|
|
3
|
+
const formatMessage = require('../common/formatMessage')
|
|
4
|
+
|
|
5
|
+
const jsAnalysis = async (config, languageFiles) => {
|
|
6
|
+
if (
|
|
7
|
+
languageFiles.JAVASCRIPT.includes('package-lock.json') &&
|
|
8
|
+
languageFiles.JAVASCRIPT.includes('yarn.lock')
|
|
9
|
+
) {
|
|
10
|
+
console.log(i18n.__('languageAnalysisMultipleLanguages1'))
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
return buildNodeTree(config, languageFiles.JAVASCRIPT)
|
|
14
|
+
}
|
|
15
|
+
const buildNodeTree = async (config, files) => {
|
|
16
|
+
let analysis = await readFiles(config, files)
|
|
17
|
+
const rawNode = await parseFiles(config, files, analysis)
|
|
18
|
+
return formatMessage.createJavaScriptTSMessage(rawNode)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const readFiles = async (config, files) => {
|
|
22
|
+
let js = {}
|
|
23
|
+
|
|
24
|
+
js.packageJSON = JSON.parse(
|
|
25
|
+
await analysis.readFile(config, files, 'package.json')
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
if (files.includes('package-lock.json')) {
|
|
29
|
+
js.rawLockFileContents = await analysis.readFile(
|
|
30
|
+
config,
|
|
31
|
+
files,
|
|
32
|
+
'package-lock.json'
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
if (files.includes('yarn.lock')) {
|
|
36
|
+
js.yarn = {}
|
|
37
|
+
js.yarn = await analysis.readYarn(config, files, 'yarn.lock')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return js
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const parseFiles = async (config, files, js) => {
|
|
44
|
+
if (files.includes('package-lock.json')) {
|
|
45
|
+
js.npmLockFile = await analysis.parseNpmLockFile(js)
|
|
46
|
+
}
|
|
47
|
+
if (files.includes('yarn.lock')) {
|
|
48
|
+
js = await analysis.parseYarnLockFile(js)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return js
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = {
|
|
55
|
+
jsAnalysis
|
|
56
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const i18n = require('i18n')
|
|
3
|
+
const _ = require('lodash')
|
|
4
|
+
|
|
5
|
+
let php = {}
|
|
6
|
+
|
|
7
|
+
const readProjectFile = (projectPath, customFile) => {
|
|
8
|
+
const filePath = filePathForWindows(projectPath + customFile)
|
|
9
|
+
try {
|
|
10
|
+
php.composerJSON = JSON.parse(fs.readFileSync(filePath, 'utf8')) //wrong here
|
|
11
|
+
php.composerJSON.dependencies = php.composerJSON.require
|
|
12
|
+
php.composerJSON.devDependencies = php.composerJSON['require-dev']
|
|
13
|
+
return php
|
|
14
|
+
} catch (err) {
|
|
15
|
+
console.log(err.message.toString())
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const readAndParseLockFile = (projectPath, customFile) => {
|
|
20
|
+
const filePath = filePathForWindows(projectPath + customFile)
|
|
21
|
+
try {
|
|
22
|
+
php.rawLockFileContents = JSON.parse(fs.readFileSync(filePath, 'utf8'))
|
|
23
|
+
php.lockFile = php.rawLockFileContents
|
|
24
|
+
let packages = _.keyBy(php.lockFile.packages, 'name')
|
|
25
|
+
let packagesDev = _.keyBy(php.lockFile['packages-dev'], 'name')
|
|
26
|
+
php.lockFile.dependencies = _.merge(packages, packagesDev)
|
|
27
|
+
|
|
28
|
+
const listOfTopDep = Object.keys(php.lockFile.dependencies)
|
|
29
|
+
|
|
30
|
+
Object.entries(php.lockFile.dependencies).forEach(([key, value]) => {
|
|
31
|
+
if (value.require) {
|
|
32
|
+
const listOfRequiresDep = Object.keys(value.require)
|
|
33
|
+
listOfRequiresDep.forEach(dep => {
|
|
34
|
+
if (!listOfTopDep.includes(dep)) {
|
|
35
|
+
addChildDepToLockFileAsOwnObj(php, value['require'], dep)
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (value['require-dev']) {
|
|
41
|
+
const listOfRequiresDep = Object.keys(value['require-dev'])
|
|
42
|
+
listOfRequiresDep.forEach(dep => {
|
|
43
|
+
if (!listOfTopDep.includes(dep)) {
|
|
44
|
+
addChildDepToLockFileAsOwnObj(php, value['require-dev'], dep)
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
formatParentDepToLockFile(php)
|
|
50
|
+
delete php.rawLockFileContents
|
|
51
|
+
return php
|
|
52
|
+
} catch (err) {
|
|
53
|
+
return console.log(i18n.__('phpParseComposerLock', php) + `${err.message}`) // not sure on this
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const getPhpDeps = (config, files) => {
|
|
58
|
+
try {
|
|
59
|
+
return (
|
|
60
|
+
readProjectFile(config.file, files[0].projectFilename),
|
|
61
|
+
readAndParseLockFile(config.file, files[1].lockFilename)
|
|
62
|
+
)
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.log(err.message.toString())
|
|
65
|
+
process.exit(1)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const filePathForWindows = path => {
|
|
70
|
+
if (process.platform === 'win32') {
|
|
71
|
+
path = path.replace(/\//g, '\\')
|
|
72
|
+
}
|
|
73
|
+
return path
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function addChildDepToLockFileAsOwnObj(php, depObj, key) {
|
|
77
|
+
php.lockFile.dependencies[key] = { version: depObj[key] }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function formatParentDepToLockFile(php) {
|
|
81
|
+
for (const [key, value] of Object.entries(php.lockFile.dependencies)) {
|
|
82
|
+
let requires = {}
|
|
83
|
+
for (const [childKey, childValue] of Object.entries(value)) {
|
|
84
|
+
if (childKey === 'require' || childKey === 'require-dev') {
|
|
85
|
+
requires = _.merge(requires, childValue)
|
|
86
|
+
php.lockFile.dependencies[key].requires = requires
|
|
87
|
+
delete php.lockFile.dependencies[key].require
|
|
88
|
+
delete php.lockFile.dependencies[key]['require-dev']
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = {
|
|
95
|
+
getPhpDeps,
|
|
96
|
+
readAndParseLockFile,
|
|
97
|
+
readProjectFile
|
|
98
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const { getPhpDeps } = require('./analysis')
|
|
2
|
+
const { createPhpTSMessage } = require('../common/formatMessage')
|
|
3
|
+
|
|
4
|
+
const phpAnalysis = (config, languageFiles) => {
|
|
5
|
+
const phpDeps = getPhpDeps(config, languageFiles.PHP)
|
|
6
|
+
return createPhpTSMessage(phpDeps)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
phpAnalysis
|
|
11
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const multiReplace = require('string-multiple-replace')
|
|
2
2
|
const fs = require('fs')
|
|
3
3
|
|
|
4
|
-
const readAndParseProjectFile =
|
|
5
|
-
const filePath = filePathForWindows(
|
|
4
|
+
const readAndParseProjectFile = file => {
|
|
5
|
+
const filePath = filePathForWindows(file + '/Pipfile')
|
|
6
6
|
const pipFile = fs.readFileSync(filePath, 'utf8')
|
|
7
7
|
|
|
8
8
|
const matcherObj = { '"': '' }
|
|
@@ -14,20 +14,21 @@ const readAndParseProjectFile = projectPath => {
|
|
|
14
14
|
return pythonArray.filter(element => element !== '' && !element.includes('#'))
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const readAndParseLockFile =
|
|
18
|
-
const filePath = filePathForWindows(
|
|
17
|
+
const readAndParseLockFile = file => {
|
|
18
|
+
const filePath = filePathForWindows(file + '/Pipfile.lock')
|
|
19
19
|
const lockFile = fs.readFileSync(filePath, 'utf8')
|
|
20
20
|
let parsedPipLock = JSON.parse(lockFile)
|
|
21
21
|
parsedPipLock['defaults'] = parsedPipLock['default']
|
|
22
|
+
delete parsedPipLock['default']
|
|
22
23
|
return parsedPipLock
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
const getPythonDeps = config => {
|
|
26
27
|
try {
|
|
27
|
-
const parseProject = readAndParseProjectFile(config.
|
|
28
|
-
const parsePip = readAndParseLockFile(config.
|
|
28
|
+
const parseProject = readAndParseProjectFile(config.file)
|
|
29
|
+
const parsePip = readAndParseLockFile(config.file)
|
|
29
30
|
|
|
30
|
-
return { pipfileLock:
|
|
31
|
+
return { pipfileLock: parsePip, pipfilDependanceies: parseProject }
|
|
31
32
|
} catch (err) {
|
|
32
33
|
console.log(err.message.toString())
|
|
33
34
|
process.exit(1)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
|
|
3
|
-
const readAndParseGemfile =
|
|
4
|
-
const fileName = filePathForWindows(
|
|
3
|
+
const readAndParseGemfile = file => {
|
|
4
|
+
const fileName = filePathForWindows(file + '/Gemfile')
|
|
5
5
|
const gemFile = fs.readFileSync(fileName, 'utf8')
|
|
6
6
|
const rubyArray = gemFile.split('\n')
|
|
7
7
|
|
|
@@ -20,8 +20,8 @@ const readAndParseGemfile = projectPath => {
|
|
|
20
20
|
return filteredRubyDep
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
const readAndParseGemLockFile =
|
|
24
|
-
const fileName = filePathForWindows(
|
|
23
|
+
const readAndParseGemLockFile = file => {
|
|
24
|
+
const fileName = filePathForWindows(file + '/Gemfile.lock')
|
|
25
25
|
const lockFile = fs.readFileSync(fileName, 'utf8')
|
|
26
26
|
const dependencyRegEx = /^\s*([A-Za-z0-9.!@#$%\-^&*_+]*)\s*(\((.*?)\))/
|
|
27
27
|
|
|
@@ -35,7 +35,7 @@ const readAndParseGemLockFile = projectPath => {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const nonDependencyKeys = (line, sourceObject) => {
|
|
38
|
-
const GEMFILE_KEY_VALUE = /^\s*([^:(]*)\s
|
|
38
|
+
const GEMFILE_KEY_VALUE = /^\s*([^:(]*)\s*\:*\s*(.*)/
|
|
39
39
|
let parts = GEMFILE_KEY_VALUE.exec(line)
|
|
40
40
|
let key = parts[1].trim()
|
|
41
41
|
let value = parts[2] || ''
|
|
@@ -206,7 +206,7 @@ const getSourceArray = (lines, dependencyRegEx) => {
|
|
|
206
206
|
if (
|
|
207
207
|
(currentWS === 4 && nexlineWS === 4) ||
|
|
208
208
|
(currentWS === 6 && nexlineWS === 4) ||
|
|
209
|
-
nexlineWS
|
|
209
|
+
nexlineWS == ''
|
|
210
210
|
) {
|
|
211
211
|
let newObj = {}
|
|
212
212
|
newObj = JSON.parse(JSON.stringify(sourceObject))
|
|
@@ -245,8 +245,8 @@ const buildSourceDependencyWithVersion = (
|
|
|
245
245
|
|
|
246
246
|
const getRubyDeps = config => {
|
|
247
247
|
try {
|
|
248
|
-
const parsedGem = readAndParseGemfile(config.
|
|
249
|
-
const parsedLock = readAndParseGemLockFile(config.
|
|
248
|
+
const parsedGem = readAndParseGemfile(config.file)
|
|
249
|
+
const parsedLock = readAndParseGemLockFile(config.file)
|
|
250
250
|
|
|
251
251
|
return { gemfilesDependanceies: parsedGem, gemfileLock: parsedLock }
|
|
252
252
|
} catch (err) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const
|
|
1
|
+
const analysis = require('./analysis')
|
|
2
2
|
const { createRubyTSMessage } = require('../common/formatMessage')
|
|
3
3
|
|
|
4
4
|
const rubyAnalysis = (config, languageFiles) => {
|
|
5
|
-
const rubyDeps = getRubyDeps(config, languageFiles.RUBY)
|
|
5
|
+
const rubyDeps = analysis.getRubyDeps(config, languageFiles.RUBY)
|
|
6
6
|
return createRubyTSMessage(rubyDeps)
|
|
7
7
|
}
|
|
8
8
|
|
|
@@ -43,18 +43,18 @@ const autoDetectAuditFilesAndLanguages = async () => {
|
|
|
43
43
|
return languagesFound
|
|
44
44
|
} else {
|
|
45
45
|
console.log(
|
|
46
|
-
'found multiple languages, please specify one using --file to run SCA
|
|
46
|
+
'found multiple languages, please specify one using --file to run SCA audit'
|
|
47
47
|
)
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
const manualDetectAuditFilesAndLanguages =
|
|
52
|
-
let projectRootFilenames = rootFile.getProjectRootFilenames(
|
|
51
|
+
const manualDetectAuditFilesAndLanguages = file => {
|
|
52
|
+
let projectRootFilenames = rootFile.getProjectRootFilenames(file)
|
|
53
53
|
let identifiedLanguages =
|
|
54
54
|
languageResolver.deduceLanguageScaAnalysis(projectRootFilenames)
|
|
55
55
|
|
|
56
56
|
if (Object.keys(identifiedLanguages).length === 0) {
|
|
57
|
-
console.log(i18n.__('languageAnalysisNoLanguage',
|
|
57
|
+
console.log(i18n.__('languageAnalysisNoLanguage', file))
|
|
58
58
|
return []
|
|
59
59
|
}
|
|
60
60
|
return [identifiedLanguages]
|