@contrast/contrast 2.0.1 → 2.0.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/audit/report/reportingFeature.js +7 -0
  2. package/dist/cliConstants.js +9 -8
  3. package/dist/commands/audit/processAudit.js +0 -2
  4. package/dist/commands/github/fingerprintConfig.js +2 -1
  5. package/dist/commands/github/processFingerprint.js +17 -7
  6. package/dist/commands/github/projectGroup.js +110 -30
  7. package/dist/commands/github/repoServices.js +42 -4
  8. package/dist/common/HTTPClient.js +37 -16
  9. package/dist/common/baseRequest.js +74 -0
  10. package/dist/constants/constants.js +1 -1
  11. package/dist/scaAnalysis/common/auditReport.js +8 -1
  12. package/dist/scaAnalysis/common/scaServicesUpload.js +3 -1
  13. package/dist/scaAnalysis/go/goReadDepFile.js +5 -1
  14. package/dist/scaAnalysis/java/analysis.js +1 -1
  15. package/dist/scaAnalysis/java/javaBuildDepsParser.js +11 -1
  16. package/dist/scaAnalysis/legacy/legacyFlow.js +0 -6
  17. package/dist/scaAnalysis/processServicesFlow.js +38 -17
  18. package/dist/scaAnalysis/repoMode/mavenParser.js +95 -53
  19. package/dist/scaAnalysis/scaAnalysis.js +4 -8
  20. package/dist/scan/autoDetection.js +12 -5
  21. package/dist/scan/fileUtils.js +33 -19
  22. package/dist/utils/paramsUtil/paramHandler.js +11 -2
  23. package/dist/utils/validationCheck.js +5 -1
  24. package/package.json +7 -3
  25. package/src/audit/report/reportingFeature.ts +7 -0
  26. package/src/cliConstants.js +9 -8
  27. package/src/commands/audit/processAudit.js +0 -2
  28. package/src/commands/github/fingerprintConfig.js +2 -2
  29. package/src/commands/github/processFingerprint.js +21 -11
  30. package/src/commands/github/projectGroup.js +131 -35
  31. package/src/commands/github/repoServices.js +46 -4
  32. package/src/common/HTTPClient.js +46 -17
  33. package/src/common/baseRequest.ts +83 -0
  34. package/src/constants/constants.js +1 -1
  35. package/src/scaAnalysis/common/auditReport.js +8 -1
  36. package/src/scaAnalysis/common/scaServicesUpload.js +5 -1
  37. package/src/scaAnalysis/go/goReadDepFile.js +5 -1
  38. package/src/scaAnalysis/java/analysis.js +1 -1
  39. package/src/scaAnalysis/java/javaBuildDepsParser.js +17 -1
  40. package/src/scaAnalysis/legacy/legacyFlow.js +0 -5
  41. package/src/scaAnalysis/processServicesFlow.js +82 -24
  42. package/src/scaAnalysis/repoMode/mavenParser.js +112 -62
  43. package/src/scaAnalysis/scaAnalysis.js +9 -8
  44. package/src/scan/autoDetection.js +12 -5
  45. package/src/scan/fileUtils.js +33 -19
  46. package/src/utils/paramsUtil/paramHandler.js +16 -2
  47. package/src/utils/validationCheck.js +6 -1
  48. package/dist/utils/settingsHelper.js +0 -14
  49. package/src/utils/settingsHelper.js +0 -16
@@ -11,8 +11,10 @@ const scaTreeUpload = async (analysis, config, reportSpinner) => {
11
11
  config.language = config.language === 'JAVASCRIPT' ? 'NODE' : config.language;
12
12
  const startTime = performance.now();
13
13
  const timeout = commonApi.getTimeout(config);
14
+ const doINeedParent = config.repositoryId && config.language === 'JAVA';
14
15
  const requestBody = {
15
- dependencyTree: analysis,
16
+ parentPom: doINeedParent ? analysis.parentPom : null,
17
+ dependencyTree: doINeedParent ? analysis.dependencyTree : analysis,
16
18
  organizationId: config.organizationId,
17
19
  language: config.language,
18
20
  tool: {
@@ -5,7 +5,10 @@ const getGoDependencies = config => {
5
5
  let cmdStdout;
6
6
  let cwd = config.file ? config.file.replace('go.mod', '') : process.cwd();
7
7
  try {
8
- cmdStdout = child_process.execSync('go mod graph', { cwd });
8
+ cmdStdout = child_process.execSync('go mod graph', {
9
+ cwd: cwd,
10
+ maxBuffer: 50 * 1024 * 1024
11
+ });
9
12
  return cmdStdout.toString();
10
13
  }
11
14
  catch (err) {
@@ -14,6 +17,7 @@ const getGoDependencies = config => {
14
17
  '\n\n*************** No transitive dependencies ***************\n\nWe are unable to build a dependency tree view from your repository as there were no transitive dependencies found.';
15
18
  }
16
19
  console.log(i18n.__('goReadProjectFile', cwd, `${err.message ? err.message : ''}`));
20
+ process.exit(1);
17
21
  }
18
22
  };
19
23
  module.exports = {
@@ -24,7 +24,7 @@ const determineProjectTypeAndCwd = (files, config) => {
24
24
  };
25
25
  const buildMaven = (config, projectData, timeout) => {
26
26
  let command = 'mvn';
27
- let args = ['dependency:tree', '-B'];
27
+ let args = ['dependency:tree', '-B', '-Dscope=runtime'];
28
28
  if (config.mavenSettingsPath) {
29
29
  args.push('-s');
30
30
  args.push(config.mavenSettingsPath);
@@ -119,7 +119,7 @@ const computeRelationToLastElement = element => {
119
119
  }
120
120
  };
121
121
  const stripElement = element => {
122
- return element
122
+ const initialStrippedElement = element
123
123
  .replace(/[|]/g, '')
124
124
  .replace('+---', '')
125
125
  .replace('\\---', '')
@@ -127,6 +127,16 @@ const stripElement = element => {
127
127
  .replace('(c)', '')
128
128
  .replace('->', '@')
129
129
  .replace('(*)', '');
130
+ const splitElements = initialStrippedElement.split(':');
131
+ if (splitElements[2] !== undefined &&
132
+ splitElements[2] !== null &&
133
+ splitElements[2].includes('@')) {
134
+ const splitVersions = splitElements[2].split('@');
135
+ return initialStrippedElement
136
+ .replace(':' + splitVersions[0], '')
137
+ .replace('@', ':');
138
+ }
139
+ return initialStrippedElement;
130
140
  };
131
141
  const checkVersion = element => {
132
142
  let version = element.split(':');
@@ -18,12 +18,6 @@ const legacyFlow = async (config, messageToSend) => {
18
18
  await pollForSnapshotCompletion(config, snapshotResponse.id, reportSpinner);
19
19
  succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
20
20
  await vulnerabilityReportV2(config, snapshotResponse.id);
21
- if (config.save !== undefined) {
22
- await auditSave(config);
23
- }
24
- else {
25
- console.log('\nUse contrast audit --save to generate an SBOM');
26
- }
27
21
  const endTime = performance.now() - startTime;
28
22
  const scanDurationMs = endTime - startTime;
29
23
  console.log(`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  const projectConfig = require('../commands/github/projectGroup');
3
+ const repoService = require('../commands/github/repoServices');
3
4
  const scaServicesUpload = require('../scaAnalysis/common/scaServicesUpload');
4
- const trackProcess = async (analysis, config, reportSpinner) => {
5
+ const dealWithNoProjectId = async (analysis, config, reportSpinner) => {
5
6
  await projectConfig.registerNewProjectGroup(config);
6
7
  let projectId = await projectConfig.getProjectIdByOrg(config);
7
8
  await projectConfig.registerProjectIdOnCliServices(config, projectId);
@@ -9,31 +10,51 @@ const trackProcess = async (analysis, config, reportSpinner) => {
9
10
  return await scaServicesUpload.scaTreeUpload(analysis, config, reportSpinner);
10
11
  };
11
12
  const repoProcess = async (analysis, config, reportSpinner) => {
12
- let repoInfo = repoService.retrieveRepoId(config);
13
- if (repoInfo.repoId === '') {
14
- repoInfo = repoService.registerRepo(config);
13
+ if (config.debug || config.verbose) {
14
+ console.log('in repository process');
15
+ console.log('repository id: ', config.repositoryId);
15
16
  }
16
- await projectConfig.registerProjectIdOnCliServices(config, repoInfo.projectId);
17
- return repoInfo;
18
- };
19
- const dealWithNoProjectId = async (analysis, config, reportSpinner) => {
20
- if (config.track) {
21
- return trackProcess(analysis, config, reportSpinner);
17
+ if (config.repositoryId === '') {
18
+ console.log('Failed to retrieve Repository Id');
19
+ process.exit(1);
22
20
  }
23
- if (!config.track) {
24
- return await scaServicesUpload.noProjectUpload(analysis, config, reportSpinner);
21
+ let repoInfo = await repoService.retrieveProjectInfoViaRepoId(config);
22
+ repoInfo = repoInfo.find(element => config.fileName === element.path &&
23
+ config.fileName === element.name &&
24
+ config.projectGroupId === element.projectGroupId);
25
+ if (config.projectGroupId &&
26
+ !repoInfo?.projectId &&
27
+ (repoInfo === undefined || repoInfo.length === 0)) {
28
+ console.log('*** has projectGroupId, no projectId and repo has no project found that matches');
29
+ repoInfo = await projectConfig.registerProjectWithGroupProjectId(config);
30
+ console.log('new registered group', repoInfo);
31
+ const language = repoInfo.language === 'JAVASCRIPT' ? 'NODE' : repoInfo.language;
32
+ await projectConfig.registerProjectIdOnCliServices(config, repoInfo.projectId);
25
33
  }
34
+ config.projectId = repoInfo.projectId;
35
+ return await scaServicesUpload.scaTreeUpload(analysis, config, reportSpinner);
26
36
  };
27
- const processUpload = async (analysis, config, reportSpinner) => {
37
+ const trackProcess = async (analysis, config, reportSpinner) => {
28
38
  let projectId = await projectConfig.getProjectIdByOrg(config);
29
39
  if (projectId === '') {
30
40
  return dealWithNoProjectId(analysis, config, reportSpinner);
31
41
  }
32
- if (projectId) {
33
- config.projectId = projectId;
34
- return await scaServicesUpload.scaTreeUpload(analysis, config, reportSpinner);
42
+ config.projectId = projectId;
43
+ await projectConfig.registerProjectIdOnCliServices(config, projectId);
44
+ return await scaServicesUpload.scaTreeUpload(analysis, config, reportSpinner);
45
+ };
46
+ const processUpload = async (analysis, config, reportSpinner) => {
47
+ if (config.repositoryId) {
48
+ return repoProcess(analysis, config, reportSpinner);
49
+ }
50
+ if (config.track) {
51
+ return trackProcess(analysis, config, reportSpinner);
52
+ }
53
+ if (!config.track) {
54
+ return await scaServicesUpload.noProjectUpload(analysis, config, reportSpinner);
35
55
  }
36
56
  };
37
57
  module.exports = {
38
- processUpload
58
+ processUpload,
59
+ repoProcess
39
60
  };
@@ -1,76 +1,118 @@
1
1
  "use strict";
2
2
  const fs = require('fs');
3
- const xml2js = require('xml2js');
3
+ const { XMLParser } = require('fast-xml-parser');
4
4
  const readPomFile = project => {
5
5
  const mavenFilePath = project.cwd + '/pom.xml';
6
6
  const projectFile = fs.readFileSync(mavenFilePath);
7
- let jsonPomFile;
8
- xml2js.parseString(projectFile, (err, result) => {
9
- if (err) {
10
- throw err;
11
- }
12
- const json = JSON.stringify(result, null);
13
- jsonPomFile = JSON.parse(json);
7
+ const parser = new XMLParser();
8
+ return parser.parse(projectFile);
9
+ };
10
+ const parsePomFile = jsonPomFile => {
11
+ console.log(JSON.stringify(jsonPomFile));
12
+ let dependencyTree = {};
13
+ let dependencies = [];
14
+ let dependencyManagement = [];
15
+ if (jsonPomFile.project && jsonPomFile.project.dependencies) {
16
+ dependencies = jsonPomFile.project.dependencies.dependency;
17
+ }
18
+ if (jsonPomFile.project && jsonPomFile.project.dependencyManagement) {
19
+ dependencyManagement =
20
+ jsonPomFile.project.dependencyManagement.dependencies.dependency;
21
+ }
22
+ const mergedAndFilteredDeps = dependencies.map(obj1 => {
23
+ const obj2 = dependencyManagement.find(obj2 => obj2.groupId === obj1.groupId && obj2.artifactId === obj1.artifactId);
24
+ return obj2 ? { ...obj1, ...obj2 } : obj1;
14
25
  });
15
- return jsonPomFile;
26
+ buildDependencies(mergedAndFilteredDeps, dependencyTree, jsonPomFile);
27
+ return {
28
+ parentPom: getParentDependency(jsonPomFile),
29
+ dependencyTree
30
+ };
16
31
  };
17
- const getFromVersionsTag = (dependencyName, versionIdentifier, jsonPomFile) => {
18
- let formattedVersion = versionIdentifier.replace(/[{}]/g, '').replace('$', '');
19
- if (jsonPomFile.project.properties[0].hasOwnProperty([formattedVersion])) {
20
- return jsonPomFile.project.properties[0][formattedVersion][0];
32
+ const getParentDependency = jsonPomFile => {
33
+ if (jsonPomFile.project && jsonPomFile.project.parent) {
34
+ return buildParent(jsonPomFile.project.parent);
35
+ }
36
+ else {
37
+ return undefined;
38
+ }
39
+ };
40
+ const buildParent = parent => {
41
+ return {
42
+ group: parent.groupId,
43
+ name: parent.artifactId,
44
+ version: parent.version
45
+ };
46
+ };
47
+ const getVersionFromParent = (parentObj, dependencyWithoutVersion) => {
48
+ const { groupId, version } = parentObj;
49
+ if (groupId === dependencyWithoutVersion.groupId) {
50
+ return version;
21
51
  }
22
52
  else {
23
53
  return null;
24
54
  }
25
55
  };
26
- const parsePomFile = jsonPomFile => {
27
- let dependencyTree = {};
28
- let parsedVersion;
29
- let dependencies;
30
- jsonPomFile.project.hasOwnProperty('dependencies')
31
- ? (dependencies = jsonPomFile.project.dependencies[0].dependency)
32
- : (dependencies =
33
- jsonPomFile.project.dependencyManagement[0].dependencies[0].dependency);
34
- for (let x in dependencies) {
35
- let dependencyObject = dependencies[x];
36
- if (!dependencyObject.hasOwnProperty('version')) {
37
- parsedVersion = getVersion(jsonPomFile, dependencyObject);
56
+ const getVersionFromProperties = (properties, dep) => {
57
+ if (properties && dep.version.includes('${')) {
58
+ const currentDepVersionPlaceholder = dep.version
59
+ .replace('${', '')
60
+ .replace('}', '');
61
+ for (const prop in properties) {
62
+ if (prop === currentDepVersionPlaceholder) {
63
+ return properties[prop];
64
+ }
38
65
  }
39
- else {
40
- dependencyObject.version[0].includes('${versions.')
41
- ? (parsedVersion = getFromVersionsTag(dependencyObject.artifactId[0], dependencyObject.version[0], jsonPomFile))
42
- : (parsedVersion = dependencyObject.version[0]);
66
+ }
67
+ };
68
+ const buildDependencies = (dependencies, dependencyTree, jsonPomFile) => {
69
+ const parent = getParentDependency(jsonPomFile);
70
+ for (const dep of dependencies) {
71
+ const versionAsString = dep.version ? dep.version.toString() : dep.version;
72
+ if (versionAsString && !versionAsString.includes('${')) {
73
+ const depName = dep.groupId + '/' + dep.artifactId + '@' + versionAsString;
74
+ dependencyTree[depName] = buildDep(dep, dep.version);
75
+ }
76
+ else if (jsonPomFile.project.properties &&
77
+ dep.version &&
78
+ dep.version.includes('${')) {
79
+ searchAndBuildFromProperties(jsonPomFile, dep, dependencyTree);
80
+ }
81
+ else if (!dep.version) {
82
+ if (parent && parent.version) {
83
+ const { parent } = jsonPomFile.project;
84
+ const parsedVersion = getVersionFromParent(parent, dep);
85
+ const depName = dep.groupId + '/' + dep.artifactId + '@' + parsedVersion;
86
+ dependencyTree[depName] = buildDep(dep, parsedVersion);
87
+ }
43
88
  }
44
- let depName = dependencyObject.groupId +
45
- '/' +
46
- dependencyObject.artifactId +
47
- '@' +
48
- parsedVersion;
49
- let parsedDependency = {
50
- name: dependencyObject.artifactId[0],
51
- group: dependencyObject.groupId[0],
52
- version: parsedVersion,
53
- directDependency: true,
54
- productionDependency: true,
55
- dependencies: []
56
- };
57
- dependencyTree[depName] = parsedDependency;
58
89
  }
59
- return dependencyTree;
60
90
  };
61
- const getVersion = (pomFile, dependencyWithoutVersion) => {
62
- let parentVersion = pomFile.project.parent[0].version[0];
63
- let parentGroupName = pomFile.project.parent[0].groupId[0];
64
- if (parentGroupName === dependencyWithoutVersion.groupId[0]) {
65
- return parentVersion;
91
+ const searchAndBuildFromProperties = (jsonPomFile, dep, dependencyTree) => {
92
+ const { properties } = jsonPomFile.project;
93
+ let versionFromProperties = getVersionFromProperties(properties, dep);
94
+ if (versionFromProperties) {
95
+ versionFromProperties = versionFromProperties.toString();
96
+ const depName = dep.groupId + '/' + dep.artifactId + '@' + versionFromProperties;
97
+ dependencyTree[depName] = buildDep(dep, versionFromProperties);
66
98
  }
67
99
  else {
68
- return null;
100
+ const depName = dep.groupId + '/' + dep.artifactId + '@' + null;
101
+ dependencyTree[depName] = buildDep(dep, null);
69
102
  }
70
103
  };
104
+ const buildDep = (dep, version) => {
105
+ return {
106
+ name: dep.artifactId,
107
+ group: dep.groupId,
108
+ version: version,
109
+ directDependency: true,
110
+ productionDependency: true,
111
+ dependencies: []
112
+ };
113
+ };
71
114
  module.exports = {
72
115
  readPomFile,
73
- getVersion,
74
- parsePomFile,
75
- getFromVersionsTag
116
+ getVersionFromParent,
117
+ parsePomFile
76
118
  };
@@ -5,7 +5,6 @@ const autoDetection = require('../scan/autoDetection');
5
5
  const rootFile = require('../audit/languageAnalysisEngine/getProjectRootFilenames');
6
6
  const path = require('path');
7
7
  const i18n = require('i18n');
8
- const auditSave = require('../audit/save');
9
8
  const { auditUsageGuide } = require('../commands/audit/help');
10
9
  const repoMode = require('./repoMode');
11
10
  const { dotNetAnalysis } = require('./dotnet');
@@ -27,6 +26,7 @@ const processSca = async (config) => {
27
26
  console.log(auditUsageGuide);
28
27
  process.exit(0);
29
28
  }
29
+ config.repo = config.repositoryId !== undefined;
30
30
  const projectStats = await rootFile.getProjectStats(config.file);
31
31
  let pathWithFile = projectStats.isFile();
32
32
  config.fileName = config.file;
@@ -34,12 +34,14 @@ const processSca = async (config) => {
34
34
  ? rootFile.getDirectoryFromPathGiven(config.file).concat('/')
35
35
  : config.file;
36
36
  filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config.file);
37
+ filesFound = await autoDetection.detectPackageManager(filesFound);
37
38
  autoDetection.dealWithMultiJava(filesFound);
38
39
  if (filesFound.length > 1 && pathWithFile) {
39
40
  filesFound = filesFound.filter(i => Object.values(i)[0].includes(path.basename(config.fileName)));
40
41
  }
41
42
  let messageToSend = undefined;
42
43
  if (filesFound.length === 1) {
44
+ config.packageManager = filesFound[0]?.packageManager;
43
45
  switch (Object.keys(filesFound[0])[0]) {
44
46
  case JAVA:
45
47
  config.language = JAVA;
@@ -99,13 +101,7 @@ const processSca = async (config) => {
99
101
  startSpinner(reportSpinner);
100
102
  let reportResponse = await processServices.processUpload(messageToSend, config, reportSpinner);
101
103
  const reportModelLibraryList = convertGenericToTypedReportModelSca(reportResponse.reportArray);
102
- auditReport.processAuditReport(config, reportModelLibraryList);
103
- if (config.save !== undefined) {
104
- await auditSave.auditSave(config, reportResponse.reportId);
105
- }
106
- else {
107
- console.log('Use contrast audit --save to generate an SBOM');
108
- }
104
+ await auditReport.processAuditReport(config, reportModelLibraryList, reportResponse.reportId);
109
105
  succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
110
106
  const endTime = performance.now() - startTime;
111
107
  const scanDurationMs = endTime - startTime;
@@ -8,11 +8,14 @@ const autoDetectFingerprintInfo = async (filePath, depth, config) => {
8
8
  let count = 0;
9
9
  complexObj.forEach(i => {
10
10
  count++;
11
- result.push({
12
- filePath: i,
13
- id: count.toString(),
14
- repositoryId: config.repositoryId
15
- });
11
+ if (!i.includes('package.json')) {
12
+ result.push({
13
+ filePath: i,
14
+ id: count.toString(),
15
+ repositoryId: config.repositoryId,
16
+ projectGroupId: config.projectGroupId
17
+ });
18
+ }
16
19
  });
17
20
  return result;
18
21
  };
@@ -40,15 +43,19 @@ const detectPackageManager = async (array) => {
40
43
  }
41
44
  if (i.filePath.includes('Pipfile')) {
42
45
  i['language'] = PYTHON;
46
+ i['packageManager'] = 'PYPI';
43
47
  }
44
48
  if (i.filePath.includes('csproj')) {
45
49
  i['language'] = DOTNET;
50
+ i['packageManager'] = 'NUGET';
46
51
  }
47
52
  if (i.filePath.includes('Gemfile')) {
48
53
  i['language'] = RUBY;
54
+ i['packageManager'] = 'RUBYGEMS';
49
55
  }
50
56
  if (i.filePath.includes('go.mod')) {
51
57
  i['language'] = GO;
58
+ i['packageManager'] = 'PKG';
52
59
  }
53
60
  });
54
61
  return array;
@@ -16,6 +16,7 @@ const findAllFiles = async (filePath, depth = 2) => {
16
16
  '**/build.gradle',
17
17
  '**/build.gradle.kts',
18
18
  '**/package.json',
19
+ '**/package-lock.json',
19
20
  '**/yarn.lock',
20
21
  '**/Pipfile',
21
22
  '**/*.csproj',
@@ -41,79 +42,92 @@ const findFilesJava = async (languagesFound, filePath, depth = 1) => {
41
42
  cwd: filePath ? filePath : process.cwd()
42
43
  });
43
44
  if (result.length > 0) {
44
- return languagesFound.push({ JAVA: result, language: 'JAVA' });
45
+ let lockFile = result.find(i => i.includes('pom') || i.includes('gradle'));
46
+ return languagesFound.push({
47
+ JAVA: result,
48
+ language: 'JAVA',
49
+ filePath: lockFile
50
+ });
45
51
  }
46
52
  return languagesFound;
47
53
  };
48
- const findFilesJavascript = async (languagesFound, filePath) => {
54
+ const findFilesJavascript = async (languagesFound, filePath, depth = 1) => {
49
55
  const result = await fg(['**/package.json', '**/yarn.lock', '**/package-lock.json'], {
50
56
  dot: false,
51
- deep: 1,
57
+ deep: depth,
52
58
  onlyFiles: true,
53
59
  cwd: filePath ? filePath : process.cwd()
54
60
  });
55
61
  if (result.length > 0) {
56
- return languagesFound.push({ JAVASCRIPT: result, language: 'JAVASCRIPT' });
62
+ let lockFile = result.find(i => i.includes('lock'));
63
+ return languagesFound.push({
64
+ JAVASCRIPT: result,
65
+ language: 'JAVASCRIPT',
66
+ filePath: lockFile
67
+ });
57
68
  }
58
69
  return languagesFound;
59
70
  };
60
- const findFilesPython = async (languagesFound, filePath) => {
71
+ const findFilesPython = async (languagesFound, filePath, depth = 1) => {
61
72
  const result = await fg(['**/Pipfile.lock', '**/Pipfile'], {
62
73
  dot: false,
63
- deep: 3,
74
+ deep: depth,
64
75
  onlyFiles: true,
65
76
  cwd: filePath ? filePath : process.cwd()
66
77
  });
67
78
  if (result.length > 0) {
68
- return languagesFound.push({ PYTHON: result });
79
+ return languagesFound.push({ PYTHON: result, filePath: 'Pipfile' });
69
80
  }
70
81
  return languagesFound;
71
82
  };
72
- const findFilesGo = async (languagesFound, filePath) => {
83
+ const findFilesGo = async (languagesFound, filePath, depth = 1) => {
73
84
  const result = await fg(['**/go.mod'], {
74
85
  dot: false,
75
- deep: 3,
86
+ deep: depth,
76
87
  onlyFiles: true,
77
88
  cwd: filePath ? filePath : process.cwd()
78
89
  });
79
90
  if (result.length > 0) {
80
- return languagesFound.push({ GO: result });
91
+ return languagesFound.push({ GO: result, filePath: 'go.mod' });
81
92
  }
82
93
  return languagesFound;
83
94
  };
84
- const findFilesRuby = async (languagesFound, filePath) => {
95
+ const findFilesRuby = async (languagesFound, filePath, depth = 1) => {
85
96
  const result = await fg(['**/Gemfile', '**/Gemfile.lock'], {
86
97
  dot: false,
87
- deep: 3,
98
+ deep: depth,
88
99
  onlyFiles: true,
89
100
  cwd: filePath ? filePath : process.cwd()
90
101
  });
91
102
  if (result.length > 0) {
92
- return languagesFound.push({ RUBY: result });
103
+ return languagesFound.push({ RUBY: result, filePath: 'Gemfile' });
93
104
  }
94
105
  return languagesFound;
95
106
  };
96
- const findFilesPhp = async (languagesFound, filePath) => {
107
+ const findFilesPhp = async (languagesFound, filePath, depth = 1) => {
97
108
  const result = await fg(['**/composer.json', '**/composer.lock'], {
98
109
  dot: false,
99
- deep: 3,
110
+ deep: depth,
100
111
  onlyFiles: true,
101
112
  cwd: filePath ? filePath : process.cwd()
102
113
  });
103
114
  if (result.length > 0) {
104
- return languagesFound.push({ PHP: result });
115
+ return languagesFound.push({ PHP: result, filePath: 'composer.lock' });
105
116
  }
106
117
  return languagesFound;
107
118
  };
108
- const findFilesDotNet = async (languagesFound, filePath) => {
119
+ const findFilesDotNet = async (languagesFound, filePath, depth = 1) => {
109
120
  const result = await fg(['**/*.csproj', '**/packages.lock.json'], {
110
121
  dot: false,
111
- deep: 3,
122
+ deep: depth,
112
123
  onlyFiles: true,
113
124
  cwd: filePath ? filePath : process.cwd()
114
125
  });
115
126
  if (result.length > 0) {
116
- return languagesFound.push({ DOTNET: result });
127
+ return languagesFound.push({
128
+ DOTNET: result,
129
+ filePath: 'packages.lock.json'
130
+ });
117
131
  }
118
132
  return languagesFound;
119
133
  };
@@ -2,7 +2,7 @@
2
2
  const commandlineAuth = require('./commandlineParams');
3
3
  const configStoreParams = require('./configStoreParams');
4
4
  const envVariableParams = require('./envVariableParams');
5
- const { validateAuthParams } = require('../validationCheck');
5
+ const { validateAuthParams, validateFingerprintParams } = require('../validationCheck');
6
6
  const i18n = require('i18n');
7
7
  const getAuth = params => {
8
8
  let commandLineAuthParamsAuth = commandlineAuth.getAuth(params);
@@ -22,4 +22,13 @@ const getAuth = params => {
22
22
  process.exit(1);
23
23
  }
24
24
  };
25
- module.exports = { getAuth };
25
+ const getFingerprint = params => {
26
+ if (validateFingerprintParams(params)) {
27
+ return params;
28
+ }
29
+ else {
30
+ console.log('missing fingerprint params please check repository-url and repository-name');
31
+ process.exit(1);
32
+ }
33
+ };
34
+ module.exports = { getAuth, getFingerprint };
@@ -19,8 +19,12 @@ const validateAuthParams = params => {
19
19
  params.host &&
20
20
  params.authorization);
21
21
  };
22
+ const validateFingerprintParams = params => {
23
+ return !!(params.repositoryUrl && params.repositoryName);
24
+ };
22
25
  module.exports = {
23
26
  checkConfigHasRequiredValues: checkConfigHasRequiredValues,
24
27
  validateAuthParams: validateAuthParams,
25
- validateRequiredScanParams: validateRequiredScanParams
28
+ validateRequiredScanParams: validateRequiredScanParams,
29
+ validateFingerprintParams: validateFingerprintParams
26
30
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/contrast",
3
- "version": "2.0.1",
3
+ "version": "2.0.2-beta.1",
4
4
  "description": "Contrast Security's command line tool",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -61,7 +61,10 @@
61
61
  "cross-spawn": "^7.0.3",
62
62
  "dotenv": "^16.0.0",
63
63
  "fast-glob": "^3.2.11",
64
+ "fast-xml-parser": "^4.2.2",
65
+ "got": "11.8.6",
64
66
  "gradle-to-js": "^2.0.1",
67
+ "hpagent": "^1.2.0",
65
68
  "i18n": "^0.15.1",
66
69
  "js-yaml": "^4.1.0",
67
70
  "lodash": "^4.17.21",
@@ -74,7 +77,7 @@
74
77
  "string-builder": "^0.1.8",
75
78
  "string-multiple-replace": "^1.0.5",
76
79
  "tmp": "^0.2.1",
77
- "xml2js": "^0.4.23",
80
+ "xml2js": "^0.5.0",
78
81
  "yarn-lockfile": "^1.1.1"
79
82
  },
80
83
  "devDependencies": {
@@ -93,8 +96,9 @@
93
96
  "eslint-plugin-prettier": "^4.2.1",
94
97
  "husky": "^3.1.0",
95
98
  "jest": "^27.5.1",
96
- "jest-junit": "^13.2.0",
99
+ "jest-junit": "^16.0.0",
97
100
  "mocha": "^10.2.0",
101
+ "nock": "^13.3.0",
98
102
  "npm-license-crawler": "^0.2.1",
99
103
  "nyc": "^15.1.0",
100
104
  "pkg": "^5.6.0",
@@ -12,6 +12,7 @@ import chalk from 'chalk'
12
12
  import * as constants from '../../constants/constants'
13
13
  import { SeverityCountModel } from './models/severityCountModel'
14
14
  import * as common from '../../common/fail'
15
+ import { auditSave } from '../save'
15
16
 
16
17
  export function convertKeysToStandardFormat(config: any, guidance: any) {
17
18
  let convertedGuidance = guidance
@@ -96,6 +97,12 @@ export async function vulnerabilityReportV2(config: any, reportId: string) {
96
97
  : {}
97
98
  )
98
99
 
100
+ if (config.save !== undefined) {
101
+ await auditSave(config)
102
+ } else {
103
+ console.log('\nUse contrast audit --save to generate an SBOM')
104
+ }
105
+
99
106
  if (config.fail) {
100
107
  common.processFail(config, output[2])
101
108
  }