@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.
Files changed (79) hide show
  1. package/dist/audit/autodetection/autoDetectLanguage.js +3 -3
  2. package/dist/audit/catalogueApplication/catalogueApplication.js +23 -5
  3. package/dist/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +5 -5
  4. package/dist/audit/languageAnalysisEngine/getProjectRootFilenames.js +9 -9
  5. package/dist/audit/languageAnalysisEngine/index.js +2 -2
  6. package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +5 -28
  7. package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +11 -4
  8. package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +39 -13
  9. package/dist/audit/languageAnalysisEngine/report/models/reportListModel.js +2 -1
  10. package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +3 -0
  11. package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +35 -14
  12. package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +3 -3
  13. package/dist/audit/save.js +29 -0
  14. package/dist/commands/audit/auditController.js +21 -5
  15. package/dist/commands/audit/help.js +24 -1
  16. package/dist/commands/audit/processAudit.js +7 -1
  17. package/dist/commands/audit/saveFile.js +7 -3
  18. package/dist/commands/scan/sca/scaAnalysis.js +31 -10
  19. package/dist/common/HTTPClient.js +6 -0
  20. package/dist/common/versionChecker.js +19 -4
  21. package/dist/constants/constants.js +1 -1
  22. package/dist/constants/locales.js +12 -11
  23. package/dist/constants.js +9 -4
  24. package/dist/index.js +4 -3
  25. package/dist/sbom/generateSbom.js +4 -3
  26. package/dist/scaAnalysis/common/formatMessage.js +26 -5
  27. package/dist/scaAnalysis/common/treeUpload.js +0 -1
  28. package/dist/scaAnalysis/go/goReadDepFile.js +1 -3
  29. package/dist/scaAnalysis/java/analysis.js +5 -5
  30. package/dist/scaAnalysis/javascript/analysis.js +110 -0
  31. package/dist/scaAnalysis/javascript/index.js +41 -0
  32. package/dist/scaAnalysis/php/analysis.js +89 -0
  33. package/dist/scaAnalysis/php/index.js +10 -0
  34. package/dist/scaAnalysis/python/analysis.js +8 -7
  35. package/dist/scaAnalysis/ruby/analysis.js +8 -8
  36. package/dist/scaAnalysis/ruby/index.js +2 -2
  37. package/dist/scan/autoDetection.js +4 -4
  38. package/dist/scan/fileUtils.js +13 -2
  39. package/dist/utils/filterProjectPath.js +7 -2
  40. package/package.json +3 -3
  41. package/src/audit/autodetection/autoDetectLanguage.ts +3 -3
  42. package/src/audit/catalogueApplication/catalogueApplication.js +28 -6
  43. package/src/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +5 -5
  44. package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +11 -11
  45. package/src/audit/languageAnalysisEngine/index.js +2 -2
  46. package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +4 -32
  47. package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +20 -19
  48. package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +67 -17
  49. package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +4 -1
  50. package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +4 -0
  51. package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +49 -17
  52. package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +1 -1
  53. package/src/audit/save.js +32 -0
  54. package/src/commands/audit/auditController.ts +22 -13
  55. package/src/commands/audit/help.ts +24 -1
  56. package/src/commands/audit/processAudit.ts +6 -3
  57. package/src/commands/audit/saveFile.ts +5 -1
  58. package/src/commands/scan/sca/scaAnalysis.js +53 -22
  59. package/src/common/HTTPClient.js +7 -0
  60. package/src/common/versionChecker.ts +23 -4
  61. package/src/constants/constants.js +1 -1
  62. package/src/constants/locales.js +12 -11
  63. package/src/constants.js +9 -4
  64. package/src/index.ts +5 -3
  65. package/src/sbom/generateSbom.ts +1 -1
  66. package/src/scaAnalysis/common/formatMessage.js +27 -5
  67. package/src/scaAnalysis/common/treeUpload.js +0 -1
  68. package/src/scaAnalysis/go/goReadDepFile.js +1 -3
  69. package/src/scaAnalysis/java/analysis.js +5 -5
  70. package/src/scaAnalysis/javascript/analysis.js +127 -0
  71. package/src/scaAnalysis/javascript/index.js +56 -0
  72. package/src/scaAnalysis/php/analysis.js +98 -0
  73. package/src/scaAnalysis/php/index.js +11 -0
  74. package/src/scaAnalysis/python/analysis.js +8 -7
  75. package/src/scaAnalysis/ruby/analysis.js +8 -8
  76. package/src/scaAnalysis/ruby/index.js +2 -2
  77. package/src/scan/autoDetection.js +4 -4
  78. package/src/scan/fileUtils.js +13 -2
  79. package/src/utils/filterProjectPath.js +6 -2
@@ -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 Analysis Failure',
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
- constantsProjectPath:
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 the --report and --cve_severity.',
140
+ 'Set the process to fail if this option is set in combination with --cve_severity.',
141
141
  failOptionErrorMessage:
142
- " FAIL - CVE's have been detected that match at least the cve_severity or cve_threshold option specified.",
142
+ ' FAIL - CVEs have been detected that match at least the cve_severity or cve_threshold option specified.',
143
143
  constantsSeverity:
144
- 'Combined with the --report command, 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 CVE's that must be exceeded to fail a build",
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
- 'Combined with the --report command excludes developer dependencies from the vulnerabilities report. By default all dependencies are included in a report.',
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 Txt text, sbom',
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: '👏 No vulnerabilities found',
400
+ scanNoVulnerabilitiesFound: '🎉 No vulnerabilities found.',
401
401
  scanNoVulnerabilitiesFoundSecureCode: '👍 Your code looks secure.',
402
- scanNoVulnerabilitiesFoundGoodWork: '👏 Keep up the good work.',
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 analysis begins',
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: 'project-path',
216
- defaultValue: process.env.PWD,
214
+ name: 'file',
215
+ alias: 'f',
216
+ defaultValue: process.cwd(),
217
217
  description:
218
218
  '{bold ' +
219
219
  i18n.__('constantsOptional') +
220
220
  '}: ' +
221
- i18n.__('constantsProjectPath')
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.get('updateMessageHidden') as boolean)
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') >= 5) {
56
- await findLatestCLIVersion(config.get('updateMessageHidden') as boolean)
57
+ if (config.get('numOfRuns') >= 1) {
58
+ await findLatestCLIVersion(config)
57
59
  config.set('numOfRuns', 0)
58
60
  }
59
61
 
@@ -1,6 +1,6 @@
1
1
  import { getHttpClient } from '../utils/commonApi'
2
2
 
3
- export default function generateSbom(config: any) {
3
+ export const generateSbom = (config: any) => {
4
4
  const client = getHttpClient(config)
5
5
  return client
6
6
  .getSbom(config)
@@ -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
- pythonDependencyTrees: pythonTree
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
  }
@@ -13,7 +13,6 @@ const commonSendSnapShot = async (analysis, config) => {
13
13
  .sendSnapshot(requestBody, config)
14
14
  .then(res => {
15
15
  if (res.statusCode === 201) {
16
- console.log('dependencies processed successfully')
17
16
  return res.body
18
17
  } else {
19
18
  console.log(res.statusCode)
@@ -3,9 +3,7 @@ const i18n = require('i18n')
3
3
 
4
4
  const getGoDependencies = config => {
5
5
  let cmdStdout
6
- let cwd = config.projectPath
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, projectPath) => {
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 = projectPath
20
- ? projectPath.replace('pom.xml', '').replace('build.gradle', '')
21
- : projectPath
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.projectPath)
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 = projectPath => {
5
- const filePath = filePathForWindows(projectPath + '/Pipfile')
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 = projectPath => {
18
- const filePath = filePathForWindows(projectPath + '/Pipfile.lock')
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.projectPath)
28
- const parsePip = readAndParseLockFile(config.projectPath)
28
+ const parseProject = readAndParseProjectFile(config.file)
29
+ const parsePip = readAndParseLockFile(config.file)
29
30
 
30
- return { pipfileLock: parseProject, pipfilDependanceies: parsePip }
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 = projectPath => {
4
- const fileName = filePathForWindows(projectPath + '/Gemfile')
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 = projectPath => {
24
- const fileName = filePathForWindows(projectPath + '/Gemfile.lock')
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*\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.projectPath)
249
- const parsedLock = readAndParseGemLockFile(config.projectPath)
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 { getRubyDeps } = require('./analysis')
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 analysis'
46
+ 'found multiple languages, please specify one using --file to run SCA audit'
47
47
  )
48
48
  }
49
49
  }
50
50
 
51
- const manualDetectAuditFilesAndLanguages = projectPath => {
52
- let projectRootFilenames = rootFile.getProjectRootFilenames(projectPath)
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', projectPath))
57
+ console.log(i18n.__('languageAnalysisNoLanguage', file))
58
58
  return []
59
59
  }
60
60
  return [identifiedLanguages]