@contrast/contrast 1.0.5 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +0 -5
- package/dist/audit/autodetection/autoDetectLanguage.js +3 -3
- package/dist/audit/catalogueApplication/catalogueApplication.js +23 -5
- package/dist/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +4 -2
- package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
- package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
- package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
- package/dist/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +5 -5
- package/dist/audit/languageAnalysisEngine/getProjectRootFilenames.js +9 -9
- package/dist/audit/languageAnalysisEngine/index.js +2 -2
- package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +6 -27
- package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +25 -5
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +99 -20
- package/dist/audit/languageAnalysisEngine/report/models/reportListModel.js +2 -1
- package/dist/audit/languageAnalysisEngine/report/models/reportOutputModel.js +24 -0
- package/dist/audit/languageAnalysisEngine/report/models/reportSeverityModel.js +3 -1
- package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +16 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +35 -14
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +58 -47
- package/dist/audit/languageAnalysisEngine/sendSnapshot.js +65 -3
- package/dist/audit/save.js +29 -0
- package/dist/commands/audit/auditController.js +22 -6
- package/dist/commands/audit/help.js +24 -1
- package/dist/commands/audit/processAudit.js +8 -2
- package/dist/commands/audit/saveFile.js +7 -3
- package/dist/commands/scan/processScan.js +1 -1
- package/dist/commands/scan/sca/scaAnalysis.js +48 -11
- package/dist/common/HTTPClient.js +56 -15
- package/dist/common/errorHandling.js +6 -1
- package/dist/common/versionChecker.js +20 -5
- package/dist/constants/constants.js +13 -3
- package/dist/constants/locales.js +15 -12
- package/dist/constants.js +9 -4
- package/dist/index.js +4 -3
- package/dist/lambda/analytics.js +11 -0
- package/dist/lambda/lambda.js +35 -4
- package/dist/lambda/types.js +13 -0
- package/dist/sbom/generateSbom.js +4 -3
- package/dist/scaAnalysis/common/formatMessage.js +46 -1
- package/dist/scaAnalysis/common/treeUpload.js +1 -3
- package/dist/scaAnalysis/go/goAnalysis.js +17 -0
- package/dist/scaAnalysis/go/goParseDeps.js +158 -0
- package/dist/scaAnalysis/go/goReadDepFile.js +21 -0
- package/dist/scaAnalysis/java/analysis.js +11 -22
- package/dist/scaAnalysis/java/index.js +6 -6
- package/dist/scaAnalysis/java/javaBuildDepsParser.js +14 -1
- package/dist/scaAnalysis/javascript/analysis.js +110 -0
- package/dist/scaAnalysis/javascript/index.js +41 -0
- package/dist/scaAnalysis/php/analysis.js +89 -0
- package/dist/scaAnalysis/php/index.js +10 -0
- package/dist/scaAnalysis/python/analysis.js +42 -0
- package/dist/scaAnalysis/python/index.js +10 -0
- package/dist/scaAnalysis/ruby/analysis.js +226 -0
- package/dist/scaAnalysis/ruby/index.js +10 -0
- package/dist/scan/autoDetection.js +8 -4
- package/dist/scan/fileUtils.js +26 -8
- package/dist/scan/formatScanOutput.js +18 -17
- package/dist/scan/models/groupedResultsModel.js +1 -1
- package/dist/scan/models/scanResultsModel.js +3 -1
- package/dist/scan/populateProjectIdAndProjectName.js +2 -1
- package/dist/scan/scan.js +5 -3
- package/dist/scan/scanConfig.js +6 -1
- package/dist/scan/scanController.js +26 -6
- package/dist/scan/scanResults.js +20 -6
- package/dist/utils/commonApi.js +4 -1
- package/dist/utils/filterProjectPath.js +7 -2
- package/dist/utils/oraWrapper.js +5 -1
- package/package.json +13 -9
- package/src/audit/autodetection/autoDetectLanguage.ts +3 -3
- package/src/audit/catalogueApplication/catalogueApplication.js +28 -7
- package/src/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +11 -8
- package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
- package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
- package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
- package/src/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +5 -5
- package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +11 -11
- package/src/audit/languageAnalysisEngine/index.js +2 -2
- package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +11 -31
- package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +35 -32
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +179 -25
- package/src/audit/languageAnalysisEngine/report/models/reportLibraryModel.ts +3 -3
- package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +18 -11
- package/src/audit/languageAnalysisEngine/report/models/reportOutputModel.ts +29 -0
- package/src/audit/languageAnalysisEngine/report/models/reportSeverityModel.ts +12 -3
- package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +20 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +50 -18
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +88 -66
- package/src/audit/languageAnalysisEngine/sendSnapshot.js +78 -3
- package/src/audit/save.js +32 -0
- package/src/commands/audit/auditController.ts +23 -15
- package/src/commands/audit/help.ts +24 -1
- package/src/commands/audit/processAudit.ts +7 -4
- package/src/commands/audit/saveFile.ts +5 -1
- package/src/commands/scan/processScan.js +2 -1
- package/src/commands/scan/sca/scaAnalysis.js +70 -29
- package/src/common/HTTPClient.js +72 -25
- package/src/common/errorHandling.ts +10 -1
- package/src/common/versionChecker.ts +24 -5
- package/src/constants/constants.js +13 -3
- package/src/constants/locales.js +15 -12
- package/src/constants.js +9 -4
- package/src/index.ts +5 -3
- package/src/lambda/analytics.ts +9 -0
- package/src/lambda/arn.ts +2 -1
- package/src/lambda/lambda.ts +37 -17
- package/src/lambda/types.ts +35 -0
- package/src/lambda/utils.ts +2 -7
- package/src/sbom/generateSbom.ts +1 -1
- package/src/scaAnalysis/common/formatMessage.js +51 -1
- package/src/scaAnalysis/common/treeUpload.js +1 -6
- package/src/scaAnalysis/go/goAnalysis.js +19 -0
- package/src/scaAnalysis/go/goParseDeps.js +203 -0
- package/src/scaAnalysis/go/goReadDepFile.js +30 -0
- package/src/scaAnalysis/java/analysis.js +15 -32
- package/src/scaAnalysis/java/index.js +6 -6
- package/src/scaAnalysis/java/javaBuildDepsParser.js +15 -2
- package/src/scaAnalysis/javascript/analysis.js +127 -0
- package/src/scaAnalysis/javascript/index.js +56 -0
- package/src/scaAnalysis/php/analysis.js +98 -0
- package/src/scaAnalysis/php/index.js +11 -0
- package/src/scaAnalysis/python/analysis.js +49 -0
- package/src/scaAnalysis/python/index.js +11 -0
- package/src/scaAnalysis/ruby/analysis.js +282 -0
- package/src/scaAnalysis/ruby/index.js +11 -0
- package/src/scan/autoDetection.js +11 -7
- package/src/scan/fileUtils.js +27 -8
- package/src/scan/formatScanOutput.ts +26 -18
- package/src/scan/models/groupedResultsModel.ts +3 -3
- package/src/scan/models/resultContentModel.ts +1 -1
- package/src/scan/models/scanResultsModel.ts +5 -2
- package/src/scan/populateProjectIdAndProjectName.js +3 -1
- package/src/scan/scan.ts +8 -6
- package/src/scan/scanConfig.js +5 -1
- package/src/scan/scanController.js +30 -9
- package/src/scan/scanResults.js +31 -10
- package/src/utils/commonApi.js +4 -1
- package/src/utils/filterProjectPath.js +6 -2
- package/src/utils/oraWrapper.js +6 -1
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const multiReplace = require('string-multiple-replace')
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
|
|
4
|
+
const readAndParseProjectFile = file => {
|
|
5
|
+
const filePath = filePathForWindows(file + '/Pipfile')
|
|
6
|
+
const pipFile = fs.readFileSync(filePath, 'utf8')
|
|
7
|
+
|
|
8
|
+
const matcherObj = { '"': '' }
|
|
9
|
+
const sequencer = ['"']
|
|
10
|
+
const parsedPipfile = multiReplace(pipFile, matcherObj, sequencer)
|
|
11
|
+
|
|
12
|
+
const pythonArray = parsedPipfile.split('\n')
|
|
13
|
+
|
|
14
|
+
return pythonArray.filter(element => element !== '' && !element.includes('#'))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const readAndParseLockFile = file => {
|
|
18
|
+
const filePath = filePathForWindows(file + '/Pipfile.lock')
|
|
19
|
+
const lockFile = fs.readFileSync(filePath, 'utf8')
|
|
20
|
+
let parsedPipLock = JSON.parse(lockFile)
|
|
21
|
+
parsedPipLock['defaults'] = parsedPipLock['default']
|
|
22
|
+
delete parsedPipLock['default']
|
|
23
|
+
return parsedPipLock
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const getPythonDeps = config => {
|
|
27
|
+
try {
|
|
28
|
+
const parseProject = readAndParseProjectFile(config.file)
|
|
29
|
+
const parsePip = readAndParseLockFile(config.file)
|
|
30
|
+
|
|
31
|
+
return { pipfileLock: parsePip, pipfilDependanceies: parseProject }
|
|
32
|
+
} catch (err) {
|
|
33
|
+
console.log(err.message.toString())
|
|
34
|
+
process.exit(1)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const filePathForWindows = path => {
|
|
39
|
+
if (process.platform === 'win32') {
|
|
40
|
+
path = path.replace(/\//g, '\\')
|
|
41
|
+
}
|
|
42
|
+
return path
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = {
|
|
46
|
+
getPythonDeps,
|
|
47
|
+
readAndParseProjectFile,
|
|
48
|
+
readAndParseLockFile
|
|
49
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const { createPythonTSMessage } = require('../common/formatMessage')
|
|
2
|
+
const { getPythonDeps } = require('./analysis')
|
|
3
|
+
|
|
4
|
+
const pythonAnalysis = (config, languageFiles) => {
|
|
5
|
+
const pythonDeps = getPythonDeps(config, languageFiles.PYTHON)
|
|
6
|
+
return createPythonTSMessage(pythonDeps)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
pythonAnalysis
|
|
11
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
|
|
3
|
+
const readAndParseGemfile = file => {
|
|
4
|
+
const fileName = filePathForWindows(file + '/Gemfile')
|
|
5
|
+
const gemFile = fs.readFileSync(fileName, 'utf8')
|
|
6
|
+
const rubyArray = gemFile.split('\n')
|
|
7
|
+
|
|
8
|
+
let filteredRubyDep = rubyArray.filter(element => {
|
|
9
|
+
return (
|
|
10
|
+
!element.includes('#') &&
|
|
11
|
+
element.includes('gem') &&
|
|
12
|
+
!element.includes('source')
|
|
13
|
+
)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
for (let i = 0; i < filteredRubyDep.length; i++) {
|
|
17
|
+
filteredRubyDep[i] = filteredRubyDep[i].trim()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return filteredRubyDep
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const readAndParseGemLockFile = file => {
|
|
24
|
+
const fileName = filePathForWindows(file + '/Gemfile.lock')
|
|
25
|
+
const lockFile = fs.readFileSync(fileName, 'utf8')
|
|
26
|
+
const dependencyRegEx = /^\s*([A-Za-z0-9.!@#$%\-^&*_+]*)\s*(\((.*?)\))/
|
|
27
|
+
|
|
28
|
+
const lines = lockFile.split('\n')
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
dependencies: getDirectDependencies(lines, dependencyRegEx),
|
|
32
|
+
runtimeDetails: getLockFileRuntimeInfo(lines),
|
|
33
|
+
sources: getSourceArray(lines, dependencyRegEx)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const nonDependencyKeys = (line, sourceObject) => {
|
|
38
|
+
const GEMFILE_KEY_VALUE = /^\s*([^:(]*)\s*\:*\s*(.*)/
|
|
39
|
+
let parts = GEMFILE_KEY_VALUE.exec(line)
|
|
40
|
+
let key = parts[1].trim()
|
|
41
|
+
let value = parts[2] || ''
|
|
42
|
+
|
|
43
|
+
sourceObject[key] = value
|
|
44
|
+
return sourceObject
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const populateResolveAndPlatform = (version, sourceObject) => {
|
|
48
|
+
const depArr = version.split('-')
|
|
49
|
+
sourceObject.resolved = depArr[0]
|
|
50
|
+
sourceObject.platform = depArr.length > 1 ? depArr[1] : 'UNSPECIFIED'
|
|
51
|
+
return sourceObject
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const isUpperCase = str => {
|
|
55
|
+
return str === str.toUpperCase()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const getDirectDependencies = (lines, dependencyRegEx) => {
|
|
59
|
+
const dependencies = {}
|
|
60
|
+
|
|
61
|
+
let depIndex = 0
|
|
62
|
+
for (let i = 0; i < lines.length; i++) {
|
|
63
|
+
if (lines[i] === 'DEPENDENCIES') {
|
|
64
|
+
depIndex = i
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const getDepArray = lines.slice(depIndex)
|
|
68
|
+
|
|
69
|
+
for (let j = 1; j < getDepArray.length; j++) {
|
|
70
|
+
const element = getDepArray[j]
|
|
71
|
+
if (!isUpperCase(element)) {
|
|
72
|
+
const isDependencyWithVersion = dependencyRegEx.test(element)
|
|
73
|
+
if (isDependencyWithVersion) {
|
|
74
|
+
const dependency = dependencyRegEx.exec(element)
|
|
75
|
+
let name = dependency[1]
|
|
76
|
+
name = name.replace('!', '')
|
|
77
|
+
dependencies[name.trim()] = dependency[3]
|
|
78
|
+
} else {
|
|
79
|
+
let name = element
|
|
80
|
+
name = name.replace('!', ' ')
|
|
81
|
+
dependencies[name.trim()] = 'UNSPECIFIED'
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return dependencies
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const getLockFileRuntimeInfo = lines => {
|
|
90
|
+
let rubVersionIndex = 0
|
|
91
|
+
for (let i = 0; i < lines.length; i++) {
|
|
92
|
+
if (lines[i] === 'RUBY VERSION') {
|
|
93
|
+
rubVersionIndex = i
|
|
94
|
+
break
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const runtimeDetails = {}
|
|
99
|
+
if (rubVersionIndex !== 0) {
|
|
100
|
+
const getRubyVersionArray = lines.slice(rubVersionIndex)
|
|
101
|
+
|
|
102
|
+
for (let element of getRubyVersionArray) {
|
|
103
|
+
if (!isUpperCase(element)) {
|
|
104
|
+
runtimeDetails['version'] = getVersion(element)
|
|
105
|
+
runtimeDetails['patchLevel'] = getPatchLevel(element)
|
|
106
|
+
|
|
107
|
+
if (element.includes('engine')) {
|
|
108
|
+
let splitElement = element.split(' ')
|
|
109
|
+
runtimeDetails[splitElement[0]] = splitElement[1]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return runtimeDetails
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const getVersion = element => {
|
|
118
|
+
const versionRegex = /^([ruby\s0-9.*]+)/
|
|
119
|
+
if (versionRegex.test(element)) {
|
|
120
|
+
let version = versionRegex.exec(element)[0]
|
|
121
|
+
|
|
122
|
+
if (version.includes('ruby')) {
|
|
123
|
+
return trimWhiteSpace(version.replace('ruby', ''))
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const getPatchLevel = element => {
|
|
129
|
+
const patchLevelRegex = /(p\d+)/
|
|
130
|
+
if (patchLevelRegex.test(element)) {
|
|
131
|
+
return patchLevelRegex.exec(element)[0]
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const formatSourceArr = sourceArr => {
|
|
136
|
+
return sourceArr.map(element => {
|
|
137
|
+
if (element.sourceType === 'GIT') {
|
|
138
|
+
delete element.specs
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (element.sourceType === 'GEM') {
|
|
142
|
+
delete element.branch
|
|
143
|
+
delete element.revision
|
|
144
|
+
delete element.depthLevel
|
|
145
|
+
delete element.specs
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (element.sourceType === 'PATH') {
|
|
149
|
+
delete element.branch
|
|
150
|
+
delete element.revision
|
|
151
|
+
delete element.depthLevel
|
|
152
|
+
delete element.specs
|
|
153
|
+
delete element.platform
|
|
154
|
+
}
|
|
155
|
+
return element
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const getSourceArray = (lines, dependencyRegEx) => {
|
|
160
|
+
const sourceObject = {
|
|
161
|
+
dependencies: {}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const whitespaceRegx = /^(\s*)/
|
|
165
|
+
let index = 0
|
|
166
|
+
|
|
167
|
+
let line = 0
|
|
168
|
+
const sources = []
|
|
169
|
+
while ((line = lines[index++]) !== undefined) {
|
|
170
|
+
let currentWS = whitespaceRegx.exec(line)[1].length
|
|
171
|
+
if (!line.includes(' bundler (')) {
|
|
172
|
+
if (currentWS === 0 && !line.includes(':') && line !== '') {
|
|
173
|
+
sourceObject.sourceType = line
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (currentWS !== 0 && line.includes(':')) {
|
|
177
|
+
nonDependencyKeys(line, sourceObject)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (currentWS > 2) {
|
|
181
|
+
let nexlineWS = whitespaceRegx.exec(lines[index])[1].length
|
|
182
|
+
sourceObject.dependencies = buildSourceDependencyWithVersion(
|
|
183
|
+
whitespaceRegx,
|
|
184
|
+
dependencyRegEx,
|
|
185
|
+
line,
|
|
186
|
+
currentWS,
|
|
187
|
+
sourceObject.name,
|
|
188
|
+
sourceObject.dependencies
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
if (currentWS === 4 && sourceObject.depthLevel === undefined) {
|
|
192
|
+
const dependency = dependencyRegEx.exec(line)
|
|
193
|
+
sourceObject.name = dependency[1]
|
|
194
|
+
sourceObject.depthLevel = currentWS
|
|
195
|
+
populateResolveAndPlatform(dependency[3], sourceObject)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (currentWS === 4 && sourceObject.depthLevel) {
|
|
199
|
+
// create new Parent
|
|
200
|
+
const dependency = dependencyRegEx.exec(line)
|
|
201
|
+
sourceObject.name = dependency[1]
|
|
202
|
+
sourceObject.depthLevel = currentWS
|
|
203
|
+
populateResolveAndPlatform(dependency[3], sourceObject)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (
|
|
207
|
+
(currentWS === 4 && nexlineWS === 4) ||
|
|
208
|
+
(currentWS === 6 && nexlineWS === 4) ||
|
|
209
|
+
nexlineWS == ''
|
|
210
|
+
) {
|
|
211
|
+
let newObj = {}
|
|
212
|
+
newObj = JSON.parse(JSON.stringify(sourceObject))
|
|
213
|
+
sources.push(newObj)
|
|
214
|
+
sourceObject.dependencies = {}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return formatSourceArr(sources)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const buildSourceDependencyWithVersion = (
|
|
223
|
+
whitespaceRegx,
|
|
224
|
+
dependencyRegEx,
|
|
225
|
+
line,
|
|
226
|
+
currentWhiteSpace,
|
|
227
|
+
name,
|
|
228
|
+
dependencies
|
|
229
|
+
) => {
|
|
230
|
+
const isDependencyWithVersion = dependencyRegEx.test(line)
|
|
231
|
+
|
|
232
|
+
if (currentWhiteSpace === 6) {
|
|
233
|
+
const dependency = dependencyRegEx.exec(line)
|
|
234
|
+
if (isDependencyWithVersion) {
|
|
235
|
+
if (name !== dependency[1]) {
|
|
236
|
+
dependencies[dependency[1]] = dependency[3]
|
|
237
|
+
}
|
|
238
|
+
} else {
|
|
239
|
+
dependencies[line.trim()] = 'UNSPECIFIED'
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return dependencies
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const getRubyDeps = config => {
|
|
247
|
+
try {
|
|
248
|
+
const parsedGem = readAndParseGemfile(config.file)
|
|
249
|
+
const parsedLock = readAndParseGemLockFile(config.file)
|
|
250
|
+
|
|
251
|
+
return { gemfilesDependanceies: parsedGem, gemfileLock: parsedLock }
|
|
252
|
+
} catch (err) {
|
|
253
|
+
console.log(err.message)
|
|
254
|
+
process.exit(1)
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const trimWhiteSpace = string => {
|
|
259
|
+
return string.replace(/\s+/g, '')
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const filePathForWindows = path => {
|
|
263
|
+
if (process.platform === 'win32') {
|
|
264
|
+
path = path.replace(/\//g, '\\')
|
|
265
|
+
}
|
|
266
|
+
return path
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
module.exports = {
|
|
270
|
+
getRubyDeps,
|
|
271
|
+
readAndParseGemfile,
|
|
272
|
+
readAndParseGemLockFile,
|
|
273
|
+
nonDependencyKeys,
|
|
274
|
+
populateResolveAndPlatform,
|
|
275
|
+
isUpperCase,
|
|
276
|
+
getDirectDependencies,
|
|
277
|
+
getLockFileRuntimeInfo,
|
|
278
|
+
getVersion,
|
|
279
|
+
getPatchLevel,
|
|
280
|
+
formatSourceArr,
|
|
281
|
+
getSourceArray
|
|
282
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const analysis = require('./analysis')
|
|
2
|
+
const { createRubyTSMessage } = require('../common/formatMessage')
|
|
3
|
+
|
|
4
|
+
const rubyAnalysis = (config, languageFiles) => {
|
|
5
|
+
const rubyDeps = analysis.getRubyDeps(config, languageFiles.RUBY)
|
|
6
|
+
return createRubyTSMessage(rubyDeps)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
rubyAnalysis
|
|
11
|
+
}
|
|
@@ -14,6 +14,11 @@ const autoDetectFileAndLanguage = async configToUse => {
|
|
|
14
14
|
process.exit(1)
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
if (fileFinder.fileIsEmpty(entries[0])) {
|
|
18
|
+
console.log(i18n.__('scanFileIsEmpty'))
|
|
19
|
+
process.exit(1)
|
|
20
|
+
}
|
|
21
|
+
|
|
17
22
|
configToUse.file = entries[0]
|
|
18
23
|
if (configToUse.name === undefined) {
|
|
19
24
|
configToUse.name = entries[0]
|
|
@@ -38,19 +43,18 @@ const autoDetectAuditFilesAndLanguages = async () => {
|
|
|
38
43
|
return languagesFound
|
|
39
44
|
} else {
|
|
40
45
|
console.log(
|
|
41
|
-
'found multiple languages, please specify one using --file to run SCA
|
|
46
|
+
'found multiple languages, please specify one using --file to run SCA audit'
|
|
42
47
|
)
|
|
43
48
|
}
|
|
44
49
|
}
|
|
45
50
|
|
|
46
|
-
const manualDetectAuditFilesAndLanguages =
|
|
47
|
-
let projectRootFilenames =
|
|
48
|
-
let identifiedLanguages =
|
|
49
|
-
projectRootFilenames
|
|
50
|
-
)
|
|
51
|
+
const manualDetectAuditFilesAndLanguages = file => {
|
|
52
|
+
let projectRootFilenames = rootFile.getProjectRootFilenames(file)
|
|
53
|
+
let identifiedLanguages =
|
|
54
|
+
languageResolver.deduceLanguageScaAnalysis(projectRootFilenames)
|
|
51
55
|
|
|
52
56
|
if (Object.keys(identifiedLanguages).length === 0) {
|
|
53
|
-
console.log(i18n.__('languageAnalysisNoLanguage',
|
|
57
|
+
console.log(i18n.__('languageAnalysisNoLanguage', file))
|
|
54
58
|
return []
|
|
55
59
|
}
|
|
56
60
|
return [identifiedLanguages]
|
package/src/scan/fileUtils.js
CHANGED
|
@@ -22,14 +22,14 @@ const findFilesJava = async languagesFound => {
|
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
if (result.length > 0) {
|
|
25
|
-
return languagesFound.push({
|
|
25
|
+
return languagesFound.push({ JAVA: result })
|
|
26
26
|
}
|
|
27
27
|
return languagesFound
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
const findFilesJavascript = async languagesFound => {
|
|
31
31
|
const result = await fg(
|
|
32
|
-
['**/package.json', '**/yarn.lock', '**/package
|
|
32
|
+
['**/package.json', '**/yarn.lock', '**/package-lock.json'],
|
|
33
33
|
{
|
|
34
34
|
dot: false,
|
|
35
35
|
deep: 1,
|
|
@@ -38,7 +38,7 @@ const findFilesJavascript = async languagesFound => {
|
|
|
38
38
|
)
|
|
39
39
|
|
|
40
40
|
if (result.length > 0) {
|
|
41
|
-
return languagesFound.push({
|
|
41
|
+
return languagesFound.push({ JAVASCRIPT: result })
|
|
42
42
|
}
|
|
43
43
|
return languagesFound
|
|
44
44
|
}
|
|
@@ -51,7 +51,7 @@ const findFilesPython = async languagesFound => {
|
|
|
51
51
|
})
|
|
52
52
|
|
|
53
53
|
if (result.length > 0) {
|
|
54
|
-
return languagesFound.push({
|
|
54
|
+
return languagesFound.push({ PYTHON: result })
|
|
55
55
|
}
|
|
56
56
|
return languagesFound
|
|
57
57
|
}
|
|
@@ -64,7 +64,7 @@ const findFilesGo = async languagesFound => {
|
|
|
64
64
|
})
|
|
65
65
|
|
|
66
66
|
if (result.length > 0) {
|
|
67
|
-
return languagesFound.push({
|
|
67
|
+
return languagesFound.push({ GO: result })
|
|
68
68
|
}
|
|
69
69
|
return languagesFound
|
|
70
70
|
}
|
|
@@ -77,7 +77,7 @@ const findFilesRuby = async languagesFound => {
|
|
|
77
77
|
})
|
|
78
78
|
|
|
79
79
|
if (result.length > 0) {
|
|
80
|
-
return languagesFound.push({
|
|
80
|
+
return languagesFound.push({ RUBY: result })
|
|
81
81
|
}
|
|
82
82
|
return languagesFound
|
|
83
83
|
}
|
|
@@ -90,7 +90,7 @@ const findFilesPhp = async languagesFound => {
|
|
|
90
90
|
})
|
|
91
91
|
|
|
92
92
|
if (result.length > 0) {
|
|
93
|
-
return languagesFound.push({
|
|
93
|
+
return languagesFound.push({ PHP: result })
|
|
94
94
|
}
|
|
95
95
|
return languagesFound
|
|
96
96
|
}
|
|
@@ -110,6 +110,24 @@ const fileExists = path => {
|
|
|
110
110
|
return fs.existsSync(path)
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
const fileIsEmpty = path => {
|
|
114
|
+
if (fileExists(path) && checkFilePermissions(path)) {
|
|
115
|
+
try {
|
|
116
|
+
return fs.readFileSync(path).length === 0
|
|
117
|
+
} catch (e) {
|
|
118
|
+
if (
|
|
119
|
+
e.message.toString().includes('illegal operation on a directory, read')
|
|
120
|
+
) {
|
|
121
|
+
console.log('file provided cannot be a directory')
|
|
122
|
+
} else {
|
|
123
|
+
console.log(e.message.toString())
|
|
124
|
+
}
|
|
125
|
+
process.exit(0)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return false
|
|
129
|
+
}
|
|
130
|
+
|
|
113
131
|
module.exports = {
|
|
114
132
|
findFile,
|
|
115
133
|
fileExists,
|
|
@@ -119,5 +137,6 @@ module.exports = {
|
|
|
119
137
|
findFilesPython,
|
|
120
138
|
findFilesGo,
|
|
121
139
|
findFilesPhp,
|
|
122
|
-
findFilesRuby
|
|
140
|
+
findFilesRuby,
|
|
141
|
+
fileIsEmpty
|
|
123
142
|
}
|