@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
@@ -4,18 +4,26 @@ const javaAnalysis = require('../../../scaAnalysis/java');
4
4
  const treeUpload = require('../../../scaAnalysis/common/treeUpload');
5
5
  const { manualDetectAuditFilesAndLanguages } = require('../../../scan/autoDetection');
6
6
  const auditController = require('../../audit/auditController');
7
- const { supportedLanguages: { JAVA, GO, RUBY, PYTHON } } = require('../../../audit/languageAnalysisEngine/constants');
7
+ const { supportedLanguages: { JAVA, GO, PYTHON, RUBY, JAVASCRIPT, NODE, PHP } } = require('../../../audit/languageAnalysisEngine/constants');
8
8
  const goAnalysis = require('../../../scaAnalysis/go/goAnalysis');
9
+ const phpAnalysis = require('../../../scaAnalysis/php/index');
9
10
  const { rubyAnalysis } = require('../../../scaAnalysis/ruby');
10
11
  const { pythonAnalysis } = require('../../../scaAnalysis/python');
12
+ const javascriptAnalysis = require('../../../scaAnalysis/javascript');
13
+ const { pollForSnapshotCompletition } = require('../../../audit/languageAnalysisEngine/sendSnapshot');
14
+ const { returnOra, startSpinner, succeedSpinner } = require('../../../utils/oraWrapper');
15
+ const i18n = require('i18n');
16
+ const { vulnerabilityReportV2 } = require('../../../audit/languageAnalysisEngine/report/reportingFeature');
17
+ const auditSave = require('../../../audit/save');
11
18
  const processSca = async (config) => {
12
19
  let filesFound;
13
- if (config.projectPath) {
14
- filesFound = manualDetectAuditFilesAndLanguages(config.projectPath);
20
+ if (config.file) {
21
+ config.file = config.file.concat('/');
22
+ filesFound = await manualDetectAuditFilesAndLanguages(config.file);
15
23
  }
16
24
  else {
17
25
  filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config);
18
- config.projectPath = process.cwd();
26
+ config.file = process.cwd().concat('/');
19
27
  }
20
28
  let messageToSend = undefined;
21
29
  if (filesFound.length === 1) {
@@ -24,14 +32,22 @@ const processSca = async (config) => {
24
32
  messageToSend = javaAnalysis.javaAnalysis(config, filesFound[0]);
25
33
  config.language = JAVA;
26
34
  break;
27
- case RUBY:
28
- messageToSend = rubyAnalysis(config, filesFound[0]);
29
- config.language = RUBY;
35
+ case JAVASCRIPT:
36
+ messageToSend = await javascriptAnalysis.jsAnalysis(config, filesFound[0]);
37
+ config.language = NODE;
30
38
  break;
31
39
  case PYTHON:
32
40
  messageToSend = pythonAnalysis(config, filesFound[0]);
33
41
  config.language = PYTHON;
34
42
  break;
43
+ case RUBY:
44
+ messageToSend = rubyAnalysis(config, filesFound[0]);
45
+ config.language = RUBY;
46
+ break;
47
+ case 'PHP':
48
+ messageToSend = phpAnalysis.phpAnalysis(config, filesFound[0]);
49
+ config.language = PHP;
50
+ break;
35
51
  case GO:
36
52
  messageToSend = goAnalysis.goAnalysis(config, filesFound[0]);
37
53
  config.language = GO;
@@ -43,15 +59,20 @@ const processSca = async (config) => {
43
59
  if (!config.applicationId) {
44
60
  config.applicationId = await auditController.dealWithNoAppId(config);
45
61
  }
46
- console.log('processing dependencies');
47
- const response = await treeUpload.commonSendSnapShot(messageToSend, config);
62
+ const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
63
+ startSpinner(reportSpinner);
64
+ const snapshotResponse = await treeUpload.commonSendSnapShot(messageToSend, config);
65
+ await pollForSnapshotCompletition(config, snapshotResponse.id, reportSpinner);
66
+ succeedSpinner(reportSpinner, 'Contrast SCA audit complete');
67
+ await vulnerabilityReportV2(config, snapshotResponse.id);
68
+ await auditSave.auditSave(config);
48
69
  }
49
70
  else {
50
71
  if (filesFound.length === 0) {
51
72
  console.log('no compatible dependency files detected. Continuing...');
52
73
  }
53
74
  else {
54
- console.log('multiple language files detected, please use --project-path to specify a directory or the file where dependencies are declared');
75
+ console.log('multiple language files detected, please use --file to specify a directory or the file where dependencies are declared');
55
76
  }
56
77
  }
57
78
  };
@@ -247,6 +247,12 @@ HTTPClient.prototype.getSbom = function getSbom(config) {
247
247
  options.url = createSbomCycloneDXUrl(config);
248
248
  return requestUtils.sendRequest({ method: 'get', options });
249
249
  };
250
+ HTTPClient.prototype.getLatestVersion = function getLatestVersion() {
251
+ const options = _.cloneDeep(this.requestOptions);
252
+ options.url =
253
+ 'https://pkg.contrastsecurity.com/artifactory/cli/latest-version.txt';
254
+ return requestUtils.sendRequest({ method: 'get', options });
255
+ };
250
256
  HTTPClient.prototype.postAnalyticsFunction = function (config, provider, body) {
251
257
  const url = createAnalyticsFunctionPostUrl(config, provider);
252
258
  const options = { ...this.requestOptions, body, url };
@@ -4,14 +4,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.isCorrectNodeVersion = exports.findLatestCLIVersion = void 0;
7
- const latest_version_1 = __importDefault(require("latest-version"));
8
7
  const constants_1 = require("../constants/constants");
9
8
  const boxen_1 = __importDefault(require("boxen"));
10
9
  const chalk_1 = __importDefault(require("chalk"));
11
10
  const semver_1 = __importDefault(require("semver"));
12
- async function findLatestCLIVersion(updateMessageHidden) {
13
- if (!updateMessageHidden) {
14
- const latestCLIVersion = await (0, latest_version_1.default)('@contrast/contrast');
11
+ const commonApi_1 = __importDefault(require("../utils/commonApi"));
12
+ const http2_1 = require("http2");
13
+ const getLatestVersion = async (config) => {
14
+ const client = commonApi_1.default.getHttpClient(config);
15
+ try {
16
+ const res = await client.getLatestVersion();
17
+ if (res.statusCode === http2_1.constants.HTTP_STATUS_OK) {
18
+ return res.body;
19
+ }
20
+ }
21
+ catch (e) {
22
+ return;
23
+ }
24
+ };
25
+ async function findLatestCLIVersion(config) {
26
+ const messageHidden = config.get('updateMessageHidden');
27
+ if (!messageHidden) {
28
+ let latestCLIVersion = await getLatestVersion(config);
29
+ latestCLIVersion = latestCLIVersion.substring(8);
15
30
  if (semver_1.default.lt(constants_1.APP_VERSION, latestCLIVersion)) {
16
31
  const updateAvailableMessage = `Update available ${chalk_1.default.yellow(constants_1.APP_VERSION)} → ${chalk_1.default.green(latestCLIVersion)}`;
17
32
  const npmUpdateAvailableCommand = `Run ${chalk_1.default.cyan('npm i @contrast/contrast -g')} to update via npm`;
@@ -12,7 +12,7 @@ const MEDIUM = 'MEDIUM';
12
12
  const HIGH = 'HIGH';
13
13
  const CRITICAL = 'CRITICAL';
14
14
  const APP_NAME = 'contrast';
15
- const APP_VERSION = '1.0.7';
15
+ const APP_VERSION = '1.0.8';
16
16
  const TIMEOUT = 120000;
17
17
  const HIGH_COLOUR = '#ff9900';
18
18
  const CRITICAL_COLOUR = '#e35858';
@@ -12,7 +12,7 @@ const en_locales = () => {
12
12
  vulnerabilitiesFailureMessage: 'Unable to retrieve library vulnerabilities',
13
13
  catchErrorMessage: 'Contrast UI error: ',
14
14
  dependenciesNote: 'Please Note: We currently only support projects with one .csproj AND *.package.lock.json',
15
- languageAnalysisFailureMessage: 'SCA Analysis Failure',
15
+ languageAnalysisFailureMessage: 'SCA audit Failure',
16
16
  languageAnalysisFactoryFailureHeader: 'FAIL',
17
17
  libraryAnalysisError: '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',
18
18
  yamlMissingParametersHeader: 'Missing Parameters',
@@ -78,7 +78,7 @@ const en_locales = () => {
78
78
  constantsApplicationName: 'The name of the application cataloged by Contrast UI',
79
79
  constantsCatalogueApplication: 'Provide this if you want to catalogue an application',
80
80
  constantsLanguage: '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',
81
- constantsProjectPath: 'The directory root of a project/application that you would like analyzed. Defaults to current directory.',
81
+ constantsFilePath: 'The directory root of a project/application that you would like analyzed. Defaults to current directory.',
82
82
  constantsSilent: 'Silences JSON output.',
83
83
  constantsAppGroups: 'Assign your application to one or more pre-existing groups when using the catalogue command. Group lists should be comma separated.',
84
84
  constantsVersion: 'Displays CLI Version you are currently on.',
@@ -90,10 +90,10 @@ const en_locales = () => {
90
90
  constantsProjectName: 'Contrast project name. If not specified, Contrast uses contrast.settings to identify the project or creates a project.',
91
91
  constantsProjectId: '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.',
92
92
  constantsReport: 'Display vulnerability information for this application',
93
- constantsFail: 'Set the process to fail if this option is set in combination with the --report and --cve_severity.',
94
- failOptionErrorMessage: " FAIL - CVE's have been detected that match at least the cve_severity or cve_threshold option specified.",
95
- constantsSeverity: '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.',
96
- constantsCount: "The number of CVE's that must be exceeded to fail a build",
93
+ constantsFail: 'Set the process to fail if this option is set in combination with --cve_severity.',
94
+ failOptionErrorMessage: ' FAIL - CVEs have been detected that match at least the cve_severity or cve_threshold option specified.',
95
+ constantsSeverity: '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.',
96
+ constantsCount: 'The number of CVEs that must be exceeded to fail a build',
97
97
  constantsHeader: 'CodeSec by Contrast Security',
98
98
  constantsPrerequisitesContentScanLanguages: 'Java & JavaScript supported',
99
99
  constantsContrastContent: "Use the 'contrast' command for fast and accurate security analysis of your applications and APIs (Java, JavaScript and .NET ) as well as serverless functions (AWS lambda, Java and Python).",
@@ -162,7 +162,7 @@ const en_locales = () => {
162
162
  constantsIgnoreCertErrors: 'For EOP users with a local Teamserver install, this will bypass the SSL certificate and recognise a self signed certificate.',
163
163
  constantsSave: 'Saves the Scan Results SARIF to file.',
164
164
  scanLabel: "adds a label to the scan - defaults to 'Started by CLI tool at current date'",
165
- constantsIgnoreDev: 'Combined with the --report command excludes developer dependencies from the vulnerabilities report. By default all dependencies are included in a report.',
165
+ constantsIgnoreDev: 'Excludes developer dependencies from the output. By default all dependencies are included.',
166
166
  constantsCommands: 'Commands',
167
167
  constantsScanOptions: 'Scan Options',
168
168
  sbomError: 'All required parameters are not present.',
@@ -277,12 +277,12 @@ const en_locales = () => {
277
277
  auditOptionsIgnoreDevDependencies: '-igd, --ignore-dev',
278
278
  auditOptionsIgnoreDevDependenciesDescription: 'ignores DevDependencies',
279
279
  auditOptionsSave: '-s, --save',
280
- auditOptionsSaveDescription: 'saves the output in specified format Txt text, sbom',
280
+ auditOptionsSaveDescription: 'saves the output in specified format, options: sbom',
281
281
  scanNotCompleted: 'Scan not completed. Check for framework and language support here: %s',
282
282
  auditNotCompleted: 'audit not completed. Please try again',
283
- scanNoVulnerabilitiesFound: '👏 No vulnerabilities found',
283
+ scanNoVulnerabilitiesFound: '🎉 No vulnerabilities found.',
284
284
  scanNoVulnerabilitiesFoundSecureCode: '👍 Your code looks secure.',
285
- scanNoVulnerabilitiesFoundGoodWork: '👏 Keep up the good work.',
285
+ scanNoVulnerabilitiesFoundGoodWork: ' Keep up the good work.',
286
286
  scanNoFiletypeSpecifiedForSave: 'Please specify file type to save results to, accepted value is SARIF',
287
287
  auditSBOMSaveSuccess: '\n Software Bill of Materials (SBOM) saved successfully',
288
288
  auditNoFiletypeSpecifiedForSave: `\n ${chalk.yellow.bold('No file type specified for --save option to save audit results to. Use audit --help to see valid --save options.')}`,
@@ -291,7 +291,8 @@ const en_locales = () => {
291
291
  auditReportFail: 'Report Retrieval Failed, please try again',
292
292
  auditReportSuccessMessage: 'Report successfully retrieved',
293
293
  auditReportFailureMessage: 'Unable to generate library report',
294
- auditSCAAnalysisBegins: 'Contrast SCA analysis begins',
294
+ auditSCAAnalysisBegins: 'Contrast SCA audit started',
295
+ auditSCAAnalysisComplete: 'Contrast SCA audit complete',
295
296
  ...lambda
296
297
  };
297
298
  };
package/dist/constants.js CHANGED
@@ -43,7 +43,6 @@ const scanOptionDefinitions = [
43
43
  },
44
44
  {
45
45
  name: 'project-path',
46
- alias: 'i',
47
46
  description: '{bold ' +
48
47
  i18n.__('constantsOptional') +
49
48
  '}: ' +
@@ -188,12 +187,13 @@ const auditOptionDefinitions = [
188
187
  i18n.__('constantsApplicationName')
189
188
  },
190
189
  {
191
- name: 'project-path',
192
- defaultValue: process.env.PWD,
190
+ name: 'file',
191
+ alias: 'f',
192
+ defaultValue: process.cwd(),
193
193
  description: '{bold ' +
194
194
  i18n.__('constantsOptional') +
195
195
  '}: ' +
196
- i18n.__('constantsProjectPath')
196
+ i18n.__('constantsFilePath')
197
197
  },
198
198
  {
199
199
  name: 'app-groups',
@@ -295,6 +295,11 @@ const auditOptionDefinitions = [
295
295
  i18n.__('constantsOptional') +
296
296
  '}: ' +
297
297
  i18n.__('auditOptionsSaveDescription')
298
+ },
299
+ {
300
+ name: 'experimental',
301
+ alias: 'e',
302
+ type: Boolean
298
303
  }
299
304
  ];
300
305
  const mainUsageGuide = commandLineUsage([
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env node
1
2
  "use strict";
2
3
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
@@ -36,12 +37,12 @@ const start = async () => {
36
37
  argvMain.includes('--v') ||
37
38
  argvMain.includes('--version')) {
38
39
  console.log(constants_2.APP_VERSION);
39
- await (0, versionChecker_1.findLatestCLIVersion)(config.get('updateMessageHidden'));
40
+ await (0, versionChecker_1.findLatestCLIVersion)(config);
40
41
  return;
41
42
  }
42
43
  config.set('numOfRuns', config.get('numOfRuns') + 1);
43
- if (config.get('numOfRuns') >= 5) {
44
- await (0, versionChecker_1.findLatestCLIVersion)(config.get('updateMessageHidden'));
44
+ if (config.get('numOfRuns') >= 1) {
45
+ await (0, versionChecker_1.findLatestCLIVersion)(config);
45
46
  config.set('numOfRuns', 0);
46
47
  }
47
48
  if (command === 'config') {
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateSbom = void 0;
3
4
  const commonApi_1 = require("../utils/commonApi");
4
- function generateSbom(config) {
5
+ const generateSbom = (config) => {
5
6
  const client = (0, commonApi_1.getHttpClient)(config);
6
7
  return client
7
8
  .getSbom(config)
@@ -16,5 +17,5 @@ function generateSbom(config) {
16
17
  .catch((err) => {
17
18
  console.log(err);
18
19
  });
19
- }
20
- exports.default = generateSbom;
20
+ };
21
+ exports.generateSbom = generateSbom;
@@ -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
+ }
19
+ else {
20
+ message.node.npmLockFile = js.npmLockFile;
21
+ }
22
+ return message;
23
+ };
9
24
  const createGoTSMessage = goTree => {
10
25
  return {
11
26
  go: {
@@ -15,21 +30,27 @@ const createGoTSMessage = goTree => {
15
30
  };
16
31
  const createRubyTSMessage = rubyTree => {
17
32
  return {
18
- ruby: {
19
- rubyDependencyTrees: rubyTree
20
- }
33
+ ruby: rubyTree
21
34
  };
22
35
  };
23
36
  const createPythonTSMessage = pythonTree => {
24
37
  return {
25
- python: {
26
- pythonDependencyTrees: pythonTree
38
+ python: pythonTree
39
+ };
40
+ };
41
+ const createPhpTSMessage = phpTree => {
42
+ return {
43
+ php: {
44
+ composerJSON: phpTree.composerJSON,
45
+ lockFile: phpTree.lockFile
27
46
  }
28
47
  };
29
48
  };
30
49
  module.exports = {
50
+ createJavaScriptTSMessage,
31
51
  createJavaTSMessage,
32
52
  createGoTSMessage,
53
+ createPhpTSMessage,
33
54
  createRubyTSMessage,
34
55
  createPythonTSMessage
35
56
  };
@@ -12,7 +12,6 @@ const commonSendSnapShot = async (analysis, config) => {
12
12
  .sendSnapshot(requestBody, config)
13
13
  .then(res => {
14
14
  if (res.statusCode === 201) {
15
- console.log('dependencies processed successfully');
16
15
  return res.body;
17
16
  }
18
17
  else {
@@ -3,9 +3,7 @@ const child_process = require('child_process');
3
3
  const i18n = require('i18n');
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
  try {
10
8
  cmdStdout = child_process.execSync('go mod graph', { cwd });
11
9
  return cmdStdout.toString();
@@ -5,7 +5,7 @@ const i18n = require('i18n');
5
5
  const fs = require('fs');
6
6
  const MAVEN = 'maven';
7
7
  const GRADLE = 'gradle';
8
- const determineProjectTypeAndCwd = (files, projectPath) => {
8
+ const determineProjectTypeAndCwd = (files, file) => {
9
9
  const projectData = {};
10
10
  if (files[0].includes('pom.xml')) {
11
11
  projectData.projectType = MAVEN;
@@ -13,9 +13,9 @@ const determineProjectTypeAndCwd = (files, projectPath) => {
13
13
  else if (files[0].includes('build.gradle')) {
14
14
  projectData.projectType = GRADLE;
15
15
  }
16
- projectData.cwd = projectPath
17
- ? projectPath.replace('pom.xml', '').replace('build.gradle', '')
18
- : projectPath;
16
+ projectData.cwd = file
17
+ ? file.replace('pom.xml', '').replace('build.gradle', '')
18
+ : file;
19
19
  return projectData;
20
20
  };
21
21
  const buildMaven = (config, projectData, timeout) => {
@@ -86,7 +86,7 @@ const getJavaBuildDeps = (config, files) => {
86
86
  projectType: undefined
87
87
  };
88
88
  try {
89
- const projectData = determineProjectTypeAndCwd(files, config.projectPath);
89
+ const projectData = determineProjectTypeAndCwd(files, config.file);
90
90
  if (projectData.projectType === MAVEN) {
91
91
  output.mvnDependancyTreeOutput = buildMaven(config, projectData, timeout);
92
92
  }
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ const fs = require('fs');
3
+ const yarnParser = require('@yarnpkg/lockfile');
4
+ const yaml = require('js-yaml');
5
+ const i18n = require('i18n');
6
+ const { formatKey } = require('../../audit/nodeAnalysisEngine/parseYarn2LockFileContents');
7
+ const readFile = async (config, languageFiles, nameOfFile) => {
8
+ const index = languageFiles.findIndex(v => v.includes(nameOfFile));
9
+ if (config.file) {
10
+ return fs.readFileSync(config.file.concat(languageFiles[index]), 'utf8');
11
+ }
12
+ else {
13
+ console.log('could not find file');
14
+ }
15
+ };
16
+ const readYarn = async (config, languageFiles, nameOfFile) => {
17
+ let yarn = {
18
+ yarnVersion: 1,
19
+ rawYarnLockFileContents: ''
20
+ };
21
+ try {
22
+ let rawYarnLockFileContents = await readFile(config, languageFiles, nameOfFile);
23
+ yarn.rawYarnLockFileContents = rawYarnLockFileContents;
24
+ if (!yarn.rawYarnLockFileContents.includes('lockfile v1') ||
25
+ yarn.rawYarnLockFileContents.includes('__metadata')) {
26
+ yarn.rawYarnLockFileContents = yaml.load(rawYarnLockFileContents);
27
+ yarn.yarnVersion = 2;
28
+ }
29
+ return yarn;
30
+ }
31
+ catch (err) {
32
+ console.log(i18n.__('nodeReadYarnLockFileError') + `${err.message}`);
33
+ return;
34
+ }
35
+ };
36
+ const parseNpmLockFile = async (js) => {
37
+ try {
38
+ js.npmLockFile = JSON.parse(js.rawLockFileContents);
39
+ if (js.npmLockFile && js.npmLockFile.lockfileVersion > 1) {
40
+ const listOfTopDep = Object.keys(js.npmLockFile.dependencies);
41
+ Object.entries(js.npmLockFile.dependencies).forEach(([objKey, value]) => {
42
+ if (value.requires) {
43
+ const listOfRequiresDep = Object.keys(value.requires);
44
+ listOfRequiresDep.forEach(dep => {
45
+ if (!listOfTopDep.includes(dep)) {
46
+ addDepToLockFile(js, value['requires'], dep);
47
+ }
48
+ });
49
+ }
50
+ if (value.dependencies) {
51
+ Object.entries(value.dependencies).forEach(([objChildKey, childValue]) => {
52
+ if (childValue.requires) {
53
+ const listOfRequiresDep = Object.keys(childValue.requires);
54
+ listOfRequiresDep.forEach(dep => {
55
+ if (!listOfTopDep.includes(dep)) {
56
+ addDepToLockFile(js, childValue['requires'], dep);
57
+ }
58
+ });
59
+ }
60
+ });
61
+ }
62
+ });
63
+ return js.npmLockFile;
64
+ }
65
+ else {
66
+ return js.npmLockFile;
67
+ }
68
+ }
69
+ catch (err) {
70
+ console.log(i18n.__('NodeParseNPM') + `${err.message}`);
71
+ return;
72
+ }
73
+ };
74
+ const addDepToLockFile = (js, depObj, key) => {
75
+ return (js.npmLockFile.dependencies[key] = { version: depObj[key] });
76
+ };
77
+ const parseYarnLockFile = async (js) => {
78
+ try {
79
+ js.yarn.yarnLockFile = {};
80
+ if (js.yarn.yarnVersion === 1) {
81
+ js.yarn.yarnLockFile = yarnParser.parse(js.yarn.rawYarnLockFileContents);
82
+ delete js.yarn.rawYarnLockFileContents;
83
+ return js;
84
+ }
85
+ else {
86
+ js.yarn.yarnLockFile['object'] = js.yarn.rawYarnLockFileContents;
87
+ delete js.yarn.yarnLockFile['object'].__metadata;
88
+ js.yarn.yarnLockFile['type'] = 'success';
89
+ Object.entries(js.yarn.rawYarnLockFileContents).forEach(([key, value]) => {
90
+ const rawKeyNames = key.split(',');
91
+ const keyNames = formatKey(rawKeyNames);
92
+ keyNames.forEach(name => {
93
+ js.yarn.yarnLockFile.object[name] = value;
94
+ });
95
+ });
96
+ return js;
97
+ }
98
+ }
99
+ catch (err) {
100
+ console.log(i18n.__('NodeParseYarn') + `${err.message}`);
101
+ return;
102
+ }
103
+ };
104
+ module.exports = {
105
+ readYarn,
106
+ parseYarnLockFile,
107
+ parseNpmLockFile,
108
+ readFile,
109
+ formatKey
110
+ };
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ const analysis = require('./analysis');
3
+ const i18n = require('i18n');
4
+ const formatMessage = require('../common/formatMessage');
5
+ const jsAnalysis = async (config, languageFiles) => {
6
+ if (languageFiles.JAVASCRIPT.includes('package-lock.json') &&
7
+ languageFiles.JAVASCRIPT.includes('yarn.lock')) {
8
+ console.log(i18n.__('languageAnalysisMultipleLanguages1'));
9
+ return;
10
+ }
11
+ return buildNodeTree(config, languageFiles.JAVASCRIPT);
12
+ };
13
+ const buildNodeTree = async (config, files) => {
14
+ let analysis = await readFiles(config, files);
15
+ const rawNode = await parseFiles(config, files, analysis);
16
+ return formatMessage.createJavaScriptTSMessage(rawNode);
17
+ };
18
+ const readFiles = async (config, files) => {
19
+ let js = {};
20
+ js.packageJSON = JSON.parse(await analysis.readFile(config, files, 'package.json'));
21
+ if (files.includes('package-lock.json')) {
22
+ js.rawLockFileContents = await analysis.readFile(config, files, 'package-lock.json');
23
+ }
24
+ if (files.includes('yarn.lock')) {
25
+ js.yarn = {};
26
+ js.yarn = await analysis.readYarn(config, files, 'yarn.lock');
27
+ }
28
+ return js;
29
+ };
30
+ const parseFiles = async (config, files, js) => {
31
+ if (files.includes('package-lock.json')) {
32
+ js.npmLockFile = await analysis.parseNpmLockFile(js);
33
+ }
34
+ if (files.includes('yarn.lock')) {
35
+ js = await analysis.parseYarnLockFile(js);
36
+ }
37
+ return js;
38
+ };
39
+ module.exports = {
40
+ jsAnalysis
41
+ };
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ const fs = require('fs');
3
+ const i18n = require('i18n');
4
+ const _ = require('lodash');
5
+ let php = {};
6
+ const readProjectFile = (projectPath, customFile) => {
7
+ const filePath = filePathForWindows(projectPath + customFile);
8
+ try {
9
+ php.composerJSON = JSON.parse(fs.readFileSync(filePath, 'utf8'));
10
+ php.composerJSON.dependencies = php.composerJSON.require;
11
+ php.composerJSON.devDependencies = php.composerJSON['require-dev'];
12
+ return php;
13
+ }
14
+ catch (err) {
15
+ console.log(err.message.toString());
16
+ }
17
+ };
18
+ const readAndParseLockFile = (projectPath, customFile) => {
19
+ const filePath = filePathForWindows(projectPath + customFile);
20
+ try {
21
+ php.rawLockFileContents = JSON.parse(fs.readFileSync(filePath, 'utf8'));
22
+ php.lockFile = php.rawLockFileContents;
23
+ let packages = _.keyBy(php.lockFile.packages, 'name');
24
+ let packagesDev = _.keyBy(php.lockFile['packages-dev'], 'name');
25
+ php.lockFile.dependencies = _.merge(packages, packagesDev);
26
+ const listOfTopDep = Object.keys(php.lockFile.dependencies);
27
+ Object.entries(php.lockFile.dependencies).forEach(([key, value]) => {
28
+ if (value.require) {
29
+ const listOfRequiresDep = Object.keys(value.require);
30
+ listOfRequiresDep.forEach(dep => {
31
+ if (!listOfTopDep.includes(dep)) {
32
+ addChildDepToLockFileAsOwnObj(php, value['require'], dep);
33
+ }
34
+ });
35
+ }
36
+ if (value['require-dev']) {
37
+ const listOfRequiresDep = Object.keys(value['require-dev']);
38
+ listOfRequiresDep.forEach(dep => {
39
+ if (!listOfTopDep.includes(dep)) {
40
+ addChildDepToLockFileAsOwnObj(php, value['require-dev'], dep);
41
+ }
42
+ });
43
+ }
44
+ });
45
+ formatParentDepToLockFile(php);
46
+ delete php.rawLockFileContents;
47
+ return php;
48
+ }
49
+ catch (err) {
50
+ return console.log(i18n.__('phpParseComposerLock', php) + `${err.message}`);
51
+ }
52
+ };
53
+ const getPhpDeps = (config, files) => {
54
+ try {
55
+ return (readProjectFile(config.file, files[0].projectFilename),
56
+ readAndParseLockFile(config.file, files[1].lockFilename));
57
+ }
58
+ catch (err) {
59
+ console.log(err.message.toString());
60
+ process.exit(1);
61
+ }
62
+ };
63
+ const filePathForWindows = path => {
64
+ if (process.platform === 'win32') {
65
+ path = path.replace(/\//g, '\\');
66
+ }
67
+ return path;
68
+ };
69
+ function addChildDepToLockFileAsOwnObj(php, depObj, key) {
70
+ php.lockFile.dependencies[key] = { version: depObj[key] };
71
+ }
72
+ function formatParentDepToLockFile(php) {
73
+ for (const [key, value] of Object.entries(php.lockFile.dependencies)) {
74
+ let requires = {};
75
+ for (const [childKey, childValue] of Object.entries(value)) {
76
+ if (childKey === 'require' || childKey === 'require-dev') {
77
+ requires = _.merge(requires, childValue);
78
+ php.lockFile.dependencies[key].requires = requires;
79
+ delete php.lockFile.dependencies[key].require;
80
+ delete php.lockFile.dependencies[key]['require-dev'];
81
+ }
82
+ }
83
+ }
84
+ }
85
+ module.exports = {
86
+ getPhpDeps,
87
+ readAndParseLockFile,
88
+ readProjectFile
89
+ };
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ const { getPhpDeps } = require('./analysis');
3
+ const { createPhpTSMessage } = require('../common/formatMessage');
4
+ const phpAnalysis = (config, languageFiles) => {
5
+ const phpDeps = getPhpDeps(config, languageFiles.PHP);
6
+ return createPhpTSMessage(phpDeps);
7
+ };
8
+ module.exports = {
9
+ phpAnalysis
10
+ };