@contrast/contrast 1.0.22 → 1.0.23

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 (39) hide show
  1. package/dist/audit/report/commonReportingFunctions.js +1 -1
  2. package/dist/audit/save.js +10 -4
  3. package/dist/commands/audit/help.js +0 -1
  4. package/dist/commands/audit/processAudit.js +1 -1
  5. package/dist/constants/constants.js +1 -1
  6. package/dist/sbom/generateSbom.js +7 -0
  7. package/dist/scaAnalysis/common/commonReportingFunctionsSca.js +3 -3
  8. package/dist/scaAnalysis/common/treeUpload.js +5 -19
  9. package/dist/scaAnalysis/go/goAnalysis.js +1 -6
  10. package/dist/scaAnalysis/java/analysis.js +24 -32
  11. package/dist/scaAnalysis/java/index.js +1 -6
  12. package/dist/scaAnalysis/javascript/index.js +1 -4
  13. package/dist/scaAnalysis/php/index.js +2 -8
  14. package/dist/scaAnalysis/python/analysis.js +4 -10
  15. package/dist/scaAnalysis/python/index.js +1 -6
  16. package/dist/scaAnalysis/ruby/analysis.js +1 -10
  17. package/dist/scaAnalysis/ruby/index.js +1 -6
  18. package/dist/scaAnalysis/scaAnalysis.js +17 -59
  19. package/package.json +2 -5
  20. package/src/audit/report/commonReportingFunctions.js +1 -1
  21. package/src/audit/save.js +11 -9
  22. package/src/commands/audit/help.js +0 -1
  23. package/src/commands/audit/processAudit.js +2 -5
  24. package/src/constants/constants.js +1 -1
  25. package/src/sbom/generateSbom.ts +8 -0
  26. package/src/scaAnalysis/common/commonReportingFunctionsSca.js +3 -3
  27. package/src/scaAnalysis/common/treeUpload.js +5 -20
  28. package/src/scaAnalysis/go/goAnalysis.js +1 -6
  29. package/src/scaAnalysis/java/analysis.js +29 -34
  30. package/src/scaAnalysis/java/index.js +1 -6
  31. package/src/scaAnalysis/javascript/index.js +1 -6
  32. package/src/scaAnalysis/php/index.js +2 -8
  33. package/src/scaAnalysis/python/analysis.js +4 -10
  34. package/src/scaAnalysis/python/index.js +1 -6
  35. package/src/scaAnalysis/ruby/analysis.js +1 -11
  36. package/src/scaAnalysis/ruby/index.js +1 -6
  37. package/src/scaAnalysis/scaAnalysis.js +25 -85
  38. package/dist/utils/settingsHelper.js +0 -24
  39. package/src/utils/settingsHelper.js +0 -26
@@ -122,7 +122,7 @@ function buildHeader(highestSeverity, contrastHeaderNum, libraryName, version, n
122
122
  function buildBody(cveArray, advice) {
123
123
  const orderedCvesWithSeverityAssigned = orderByHighestPriority(cveArray.map(cve => findCVESeverity(cve)));
124
124
  const issueMessage = getIssueRow(orderedCvesWithSeverityAssigned);
125
- const minOrMax = advice.maximum ? advice.maximum : advice.minimum;
125
+ const minOrMax = advice.minimum ? advice.minimum : advice.maximum;
126
126
  const displayAdvice = minOrMax
127
127
  ? `Change to version ${chalk.bold(minOrMax)}`
128
128
  : 'No recommendation is available according to our data. Upgrade to the latest stable is the best advice we can give.';
@@ -19,18 +19,24 @@ async function auditSave(config, reportId) {
19
19
  break;
20
20
  }
21
21
  if (fileFormat) {
22
- if (config.experimental) {
23
- save.saveFile(config, fileFormat, await sbom.generateSCASbom(config, fileFormat, reportId));
22
+ if (config.legacy === false) {
23
+ const sbomResponse = await sbom.generateSCASbom(config, fileFormat, reportId);
24
+ if (sbomResponse) {
25
+ save.saveFile(config, fileFormat, sbomResponse);
26
+ }
24
27
  }
25
28
  else {
26
- save.saveFile(config, fileFormat, await sbom.generateSbom(config, fileFormat));
29
+ const sbomResponse = await sbom.generateSbom(config, fileFormat);
30
+ if (sbomResponse) {
31
+ save.saveFile(config, fileFormat, sbomResponse);
32
+ }
27
33
  }
28
34
  const filename = `${config.applicationId}-sbom-${fileFormat}.json`;
29
35
  if (fs.existsSync(filename)) {
30
36
  console.log(i18n.__('auditSBOMSaveSuccess') + ` - ${filename}`);
31
37
  }
32
38
  else {
33
- console.log(chalk.yellow.bold(`\n Unable to save ${filename} Software Bill of Materials (SBOM)`));
39
+ console.log(chalk.yellow.bold(`\nUnable to save ${filename} Software Bill of Materials (SBOM)`));
34
40
  }
35
41
  }
36
42
  else {
@@ -51,7 +51,6 @@ const auditUsageGuide = commandLineUsage([
51
51
  'code',
52
52
  'maven-settings-path',
53
53
  'language',
54
- 'experimental',
55
54
  'app-groups',
56
55
  'metadata',
57
56
  'track',
@@ -9,7 +9,7 @@ const processAudit = async (contrastConf, argvMain) => {
9
9
  printHelpMessage();
10
10
  process.exit(0);
11
11
  }
12
- const config = await auditConfig.getAuditConfig(contrastConf, 'audit', argvMain);
12
+ let config = await auditConfig.getAuditConfig(contrastConf, 'audit', argvMain);
13
13
  await scaController.processSca(config);
14
14
  if (!config.fingerprint) {
15
15
  postRunMessage('audit');
@@ -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.22';
15
+ const APP_VERSION = '1.0.23';
16
16
  const TIMEOUT = 120000;
17
17
  const HIGH_COLOUR = '#ff9900';
18
18
  const CRITICAL_COLOUR = '#e35858';
@@ -10,8 +10,14 @@ const generateSbom = (config, type) => {
10
10
  if (res.statusCode === 200) {
11
11
  return res.body;
12
12
  }
13
+ else if (res.statusCode === 403) {
14
+ console.log('\nUnable to retrieve Software Bill of Materials (SBOM)');
15
+ console.log(`Please ensure OSS is enabled for your organization - org-id ${config.organizationId} and app ${config.applicationId}`);
16
+ return undefined;
17
+ }
13
18
  else {
14
19
  console.log('Unable to retrieve Software Bill of Materials (SBOM)');
20
+ return undefined;
15
21
  }
16
22
  })
17
23
  .catch((err) => {
@@ -29,6 +35,7 @@ const generateSCASbom = (config, type, reportId) => {
29
35
  }
30
36
  else {
31
37
  console.log('Unable to retrieve Software Bill of Materials (SBOM)');
38
+ return undefined;
32
39
  }
33
40
  })
34
41
  .catch((err) => {
@@ -104,9 +104,9 @@ function getIssueRow(cveArray) {
104
104
  return [chalk.bold('Issue'), ':', `${cveMessagesList.join(', ')}`];
105
105
  }
106
106
  function getAdviceRow(advice) {
107
- const latestOrClosest = advice.latestStableVersion
108
- ? advice.latestStableVersion
109
- : advice.closestStableVersion;
107
+ const latestOrClosest = advice.closestStableVersion
108
+ ? advice.closestStableVersion
109
+ : advice.latestStableVersion;
110
110
  const displayAdvice = latestOrClosest
111
111
  ? `Change to version ${chalk.bold(latestOrClosest)}`
112
112
  : 'No recommendation is available according to our data. Upgrade to the latest stable is the best advice we can give.';
@@ -3,13 +3,11 @@ const commonApi = require('../../utils/commonApi');
3
3
  const { APP_VERSION } = require('../../constants/constants');
4
4
  const commonSendSnapShot = async (analysis, config) => {
5
5
  let requestBody = {};
6
- config.experimental === true
7
- ? (requestBody = sendToSCAServices(config, analysis))
8
- : (requestBody = {
9
- appID: config.applicationId,
10
- cliVersion: APP_VERSION,
11
- snapshot: analysis
12
- });
6
+ requestBody = {
7
+ appID: config.applicationId,
8
+ cliVersion: APP_VERSION,
9
+ snapshot: analysis
10
+ };
13
11
  const client = commonApi.getHttpClient(config);
14
12
  return client
15
13
  .sendSnapshot(requestBody, config)
@@ -28,18 +26,6 @@ const commonSendSnapShot = async (analysis, config) => {
28
26
  throw err;
29
27
  });
30
28
  };
31
- const sendToSCAServices = (config, analysis) => {
32
- return {
33
- applicationId: config.applicationId,
34
- dependencyTree: analysis,
35
- organizationId: config.organizationId,
36
- language: config.language,
37
- tool: {
38
- name: 'Contrast Codesec',
39
- version: APP_VERSION
40
- }
41
- };
42
- };
43
29
  module.exports = {
44
30
  commonSendSnapShot
45
31
  };
@@ -7,12 +7,7 @@ const goAnalysis = config => {
7
7
  try {
8
8
  const rawGoDependencies = goReadDepFile.getGoDependencies(config);
9
9
  const parsedGoDependencies = goParseDeps.parseGoDependencies(rawGoDependencies);
10
- if (config.experimental) {
11
- return parseDependenciesForSCAServices(parsedGoDependencies);
12
- }
13
- else {
14
- return createGoTSMessage(parsedGoDependencies);
15
- }
10
+ return createGoTSMessage(parsedGoDependencies);
16
11
  }
17
12
  catch (e) {
18
13
  console.log(e.message.toString());
@@ -4,8 +4,6 @@ const spawn = require('cross-spawn');
4
4
  const path = require('path');
5
5
  const i18n = require('i18n');
6
6
  const fs = require('fs');
7
- const readLine = require('readline');
8
- const paramHandler = require('../../utils/paramsUtil/paramHandler');
9
7
  const MAVEN = 'maven';
10
8
  const GRADLE = 'gradle';
11
9
  const determineProjectTypeAndCwd = (files, config) => {
@@ -25,26 +23,25 @@ const determineProjectTypeAndCwd = (files, config) => {
25
23
  return projectData;
26
24
  };
27
25
  const buildMaven = (config, projectData, timeout) => {
28
- let cmdStdout;
29
- try {
30
- let command = 'mvn';
31
- let args = ['dependency:tree', '-B'];
32
- if (config.mavenSettingsPath) {
33
- args.push('-s');
34
- args.push(config.mavenSettingsPath);
35
- }
36
- cmdStdout = spawn
37
- .sync(command, args, {
38
- env: process.env,
39
- cwd: projectData.cwd,
40
- timeout
41
- })
42
- .stdout.toString();
43
- return cmdStdout.toString();
26
+ let command = 'mvn';
27
+ let args = ['dependency:tree', '-B'];
28
+ if (config.mavenSettingsPath) {
29
+ args.push('-s');
30
+ args.push(config.mavenSettingsPath);
44
31
  }
45
- catch (err) {
46
- throw new Error(i18n.__('mavenDependencyTreeNonZero', projectData.cwd, `${err.message}`));
32
+ const cmdDepTree = spawn.sync(command, args, {
33
+ env: process.env,
34
+ cwd: projectData.cwd,
35
+ timeout
36
+ });
37
+ if (cmdDepTree.status !== 0) {
38
+ if (config.debug && cmdDepTree.error.code === 'ENOENT') {
39
+ console.log(`ERROR: mvn not found`);
40
+ console.log('Please make sure mvn is installed and accessible');
41
+ }
42
+ throw new Error(i18n.__('mavenDependencyTreeNonZero', projectData.cwd));
47
43
  }
44
+ return cmdDepTree.stdout.toString();
48
45
  };
49
46
  const buildGradle = (config, projectData, timeout) => {
50
47
  let cmdStdout;
@@ -96,20 +93,15 @@ const getJavaBuildDeps = (config, files) => {
96
93
  mvnDependancyTreeOutput: undefined,
97
94
  projectType: undefined
98
95
  };
99
- try {
100
- const projectData = determineProjectTypeAndCwd(files, config);
101
- if (projectData.projectType === MAVEN) {
102
- output.mvnDependancyTreeOutput = buildMaven(config, projectData, timeout);
103
- }
104
- else if (projectData.projectType === GRADLE) {
105
- output.mvnDependancyTreeOutput = buildGradle(config, projectData, timeout);
106
- }
107
- output.projectType = projectData.projectType;
108
- return output;
96
+ const projectData = determineProjectTypeAndCwd(files, config);
97
+ if (projectData.projectType === MAVEN) {
98
+ output.mvnDependancyTreeOutput = buildMaven(config, projectData, timeout);
109
99
  }
110
- catch (err) {
111
- console.log(err.message.toString());
100
+ else if (projectData.projectType === GRADLE) {
101
+ output.mvnDependancyTreeOutput = buildGradle(config, projectData, timeout);
112
102
  }
103
+ output.projectType = projectData.projectType;
104
+ return output;
113
105
  };
114
106
  module.exports = {
115
107
  getJavaBuildDeps,
@@ -8,12 +8,7 @@ const javaAnalysis = async (config, languageFiles) => {
8
8
  file.replace('build.gradle.kts', 'build.gradle');
9
9
  });
10
10
  const javaDeps = buildJavaTree(config, languageFiles.JAVA);
11
- if (config.experimental) {
12
- return parseDependenciesForSCAServices(javaDeps);
13
- }
14
- else {
15
- return createJavaTSMessage(javaDeps);
16
- }
11
+ return createJavaTSMessage(javaDeps);
17
12
  };
18
13
  const buildJavaTree = (config, files) => {
19
14
  const javaBuildDeps = analysis.getJavaBuildDeps(config, files);
@@ -13,9 +13,6 @@ const jsAnalysis = async (config, languageFiles) => {
13
13
  const buildNodeTree = async (config, files) => {
14
14
  let analysis = await readFiles(config, files);
15
15
  const rawNode = await parseFiles(config, files, analysis);
16
- if (config.experimental) {
17
- return scaServiceParser.parseJS(rawNode);
18
- }
19
16
  return formatMessage.createJavaScriptTSMessage(rawNode);
20
17
  };
21
18
  const readFiles = async (config, files) => {
@@ -42,7 +39,7 @@ const parseFiles = async (config, files, js) => {
42
39
  if (!currentLockFileVersion || !npmLockFile.packages) {
43
40
  throw new Error(`package-lock.json needs to be in the NPM v2 or v3 format. \n ${generalRebuildMessage}`);
44
41
  }
45
- if (currentLockFileVersion === 3 && !config.experimental) {
42
+ if (currentLockFileVersion === 3) {
46
43
  throw new Error(`NPM lockfileVersion 3 is only supported when using the '-e' flag.`);
47
44
  }
48
45
  js.npmLockFile = await analysis.parseNpmLockFile(npmLockFile);
@@ -1,16 +1,10 @@
1
1
  "use strict";
2
2
  const { readFile, parseProjectFiles } = require('./analysis');
3
3
  const { createPhpTSMessage } = require('../common/formatMessage');
4
- const { parsePHPLockFileForScaServices } = require('./phpNewServicesMapper');
5
4
  const phpAnalysis = config => {
6
5
  let analysis = readFiles(config);
7
- if (config.experimental) {
8
- return parsePHPLockFileForScaServices(analysis.rawLockFileContents);
9
- }
10
- else {
11
- const phpDep = parseProjectFiles(analysis);
12
- return createPhpTSMessage(phpDep);
13
- }
6
+ const phpDep = parseProjectFiles(analysis);
7
+ return createPhpTSMessage(phpDep);
14
8
  };
15
9
  const readFiles = config => {
16
10
  let php = {};
@@ -48,16 +48,10 @@ const checkForCorrectFiles = languageFiles => {
48
48
  };
49
49
  const getPythonDeps = (config, languageFiles) => {
50
50
  try {
51
- if (config.experimental) {
52
- let pythonLockFileContents = readLockFile(config.file);
53
- return scaPythonParser(pythonLockFileContents);
54
- }
55
- else {
56
- checkForCorrectFiles(languageFiles);
57
- const parseProject = readAndParseProjectFile(config.file);
58
- const parsePip = readAndParseLockFile(config.file);
59
- return { pipfileLock: parsePip, pipfilDependanceies: parseProject };
60
- }
51
+ checkForCorrectFiles(languageFiles);
52
+ const parseProject = readAndParseProjectFile(config.file);
53
+ const parsePip = readAndParseLockFile(config.file);
54
+ return { pipfileLock: parsePip, pipfilDependanceies: parseProject };
61
55
  }
62
56
  catch (err) {
63
57
  console.log(err.message.toString());
@@ -3,12 +3,7 @@ const { createPythonTSMessage } = require('../common/formatMessage');
3
3
  const { getPythonDeps, secondaryParser } = require('./analysis');
4
4
  const pythonAnalysis = (config, languageFiles) => {
5
5
  const pythonDeps = getPythonDeps(config, languageFiles.PYTHON);
6
- if (config.experimental) {
7
- return pythonDeps;
8
- }
9
- else {
10
- return createPythonTSMessage(pythonDeps);
11
- }
6
+ return createPythonTSMessage(pythonDeps);
12
7
  };
13
8
  module.exports = {
14
9
  pythonAnalysis
@@ -6,16 +6,7 @@ const getRubyDeps = (config, languageFiles) => {
6
6
  checkForCorrectFiles(languageFiles);
7
7
  const parsedGem = readAndParseGemfile(config.file);
8
8
  const parsedLock = readAndParseGemLockFile(config.file);
9
- if (config.experimental) {
10
- const rubyArray = removeRedundantAndPopulateDefinedElements(parsedLock.sources);
11
- let rubyTree = createRubyTree(rubyArray);
12
- findChildrenDependencies(rubyTree);
13
- processRootDependencies(parsedLock.dependencies, rubyTree);
14
- return rubyTree;
15
- }
16
- else {
17
- return { gemfilesDependanceies: parsedGem, gemfileLock: parsedLock };
18
- }
9
+ return { gemfilesDependanceies: parsedGem, gemfileLock: parsedLock };
19
10
  }
20
11
  catch (err) {
21
12
  throw err;
@@ -3,12 +3,7 @@ const analysis = require('./analysis');
3
3
  const { createRubyTSMessage } = require('../common/formatMessage');
4
4
  const rubyAnalysis = (config, languageFiles) => {
5
5
  const rubyDeps = analysis.getRubyDeps(config, languageFiles.RUBY);
6
- if (config.experimental) {
7
- return rubyDeps;
8
- }
9
- else {
10
- return createRubyTSMessage(rubyDeps);
11
- }
6
+ return createRubyTSMessage(rubyDeps);
12
7
  };
13
8
  module.exports = {
14
9
  rubyAnalysis
@@ -19,14 +19,8 @@ const { rubyAnalysis } = require('./ruby');
19
19
  const { pythonAnalysis } = require('./python');
20
20
  const javaAnalysis = require('./java');
21
21
  const jsAnalysis = require('./javascript');
22
- const auditReport = require('./common/auditReport');
23
- const scaUpload = require('./common/scaServicesUpload');
24
- const settingsHelper = require('../utils/settingsHelper');
25
22
  const chalk = require('chalk');
26
- const saveResults = require('../scan/saveResults');
27
- const { convertGenericToTypedReportModelSca } = require('./common/utils/reportUtilsSca');
28
23
  const processSca = async (config) => {
29
- config = await settingsHelper.getSettings(config);
30
24
  const startTime = performance.now();
31
25
  let filesFound;
32
26
  if (config.help) {
@@ -49,17 +43,7 @@ const processSca = async (config) => {
49
43
  switch (Object.keys(filesFound[0])[0]) {
50
44
  case JAVA:
51
45
  config.language = JAVA;
52
- if (config.mode === 'repo') {
53
- try {
54
- return repoMode.buildRepo(config, filesFound[0]);
55
- }
56
- catch (e) {
57
- throw new Error('Unable to build in repository mode. Check your project file');
58
- }
59
- }
60
- else {
61
- messageToSend = await javaAnalysis.javaAnalysis(config, filesFound[0]);
62
- }
46
+ messageToSend = await javaAnalysis.javaAnalysis(config, filesFound[0]);
63
47
  break;
64
48
  case JAVASCRIPT:
65
49
  messageToSend = await jsAnalysis.jsAnalysis(config, filesFound[0]);
@@ -82,15 +66,9 @@ const processSca = async (config) => {
82
66
  config.language = GO;
83
67
  break;
84
68
  case DOTNET:
85
- if (config.experimental) {
86
- console.log(`${chalk.bold('\n.NET project found\n')} Language type is unsupported.`);
87
- return;
88
- }
89
- else {
90
- messageToSend = dotNetAnalysis(config, filesFound[0]);
91
- config.language = DOTNET;
92
- break;
93
- }
69
+ messageToSend = dotNetAnalysis(config, filesFound[0]);
70
+ config.language = DOTNET;
71
+ break;
94
72
  default:
95
73
  console.log('No supported language detected in project path');
96
74
  return;
@@ -98,42 +76,22 @@ const processSca = async (config) => {
98
76
  if (!config.applicationId) {
99
77
  config.applicationId = await auditController.dealWithNoAppId(config);
100
78
  }
101
- if (config.experimental) {
102
- console.log('');
103
- const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
104
- startSpinner(reportSpinner);
105
- const { reportArray, reportId } = await scaUpload.scaTreeUpload(messageToSend, config);
106
- const reportModelLibraryList = convertGenericToTypedReportModelSca(reportArray);
107
- auditReport.processAuditReport(config, reportModelLibraryList);
108
- succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
109
- if (config.save !== undefined) {
110
- await auditSave.auditSave(config, reportId);
111
- }
112
- else {
113
- console.log('Use contrast audit --save to generate an SBOM');
114
- }
115
- const endTime = performance.now() - startTime;
116
- const scanDurationMs = endTime - startTime;
117
- console.log(`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
79
+ console.log('');
80
+ const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
81
+ startSpinner(reportSpinner);
82
+ const snapshotResponse = await treeUpload.commonSendSnapShot(messageToSend, config);
83
+ await pollForSnapshotCompletion(config, snapshotResponse.id, reportSpinner);
84
+ succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
85
+ await vulnerabilityReportV2(config, snapshotResponse.id);
86
+ if (config.save !== undefined) {
87
+ await auditSave.auditSave(config);
118
88
  }
119
89
  else {
120
- console.log('');
121
- const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'));
122
- startSpinner(reportSpinner);
123
- const snapshotResponse = await treeUpload.commonSendSnapShot(messageToSend, config);
124
- await pollForSnapshotCompletion(config, snapshotResponse.id, reportSpinner);
125
- succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
126
- await vulnerabilityReportV2(config, snapshotResponse.id);
127
- if (config.save !== undefined) {
128
- await auditSave.auditSave(config);
129
- }
130
- else {
131
- console.log('\nUse contrast audit --save to generate an SBOM');
132
- }
133
- const endTime = performance.now() - startTime;
134
- const scanDurationMs = endTime - startTime;
135
- console.log(`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
90
+ console.log('\nUse contrast audit --save to generate an SBOM');
136
91
  }
92
+ const endTime = performance.now() - startTime;
93
+ const scanDurationMs = endTime - startTime;
94
+ console.log(`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
137
95
  }
138
96
  else {
139
97
  if (filesFound.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/contrast",
3
- "version": "1.0.22",
3
+ "version": "1.0.23",
4
4
  "description": "Contrast Security's command line tool",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -27,12 +27,9 @@
27
27
  "test": "jest --testPathIgnorePatterns=./test-integration/",
28
28
  "test-int": "jest ./test-integration/",
29
29
  "test-int-scan": "jest ./test-integration/scan",
30
- "test-int-audit": "jest test-integration/audit",
31
- "test-int-audit-reports": "jest test-integration/audit/audit-language-reports.spec.js",
32
30
  "test-int-scan-errors": "jest test-integration/scan/scanLocalErrors.spec.js",
33
31
  "test-int-scan-reports": "jest test-integration/scan/scanReport.spec.js",
34
- "test-int-audit-features": "jest test-integration/audit/auditFeatures/",
35
- "test-int-audit-experimental": "jest test-integration/audit/audit-experimental.spec.js",
32
+ "test-int-audit-features": "jest test-integration/audit/auditFeatures",
36
33
  "format": "prettier --write \"**/*.{ts,tsx,js,json,md,yml}\" .eslintrc.*",
37
34
  "check-format": "prettier --check \"**/*.{ts,tsx,js,json,md,yml}\" .eslintrc.*",
38
35
  "coverage-local": "nyc --reporter=text mocha './test/**/*.spec.js'",
@@ -247,7 +247,7 @@ function buildBody(cveArray, advice) {
247
247
  //todo different advice based on remediationGuidance being available or now
248
248
  // console.log(advice)
249
249
 
250
- const minOrMax = advice.maximum ? advice.maximum : advice.minimum
250
+ const minOrMax = advice.minimum ? advice.minimum : advice.maximum
251
251
  const displayAdvice = minOrMax
252
252
  ? `Change to version ${chalk.bold(minOrMax)}`
253
253
  : 'No recommendation is available according to our data. Upgrade to the latest stable is the best advice we can give.'
package/src/audit/save.js CHANGED
@@ -23,18 +23,20 @@ async function auditSave(config, reportId) {
23
23
  }
24
24
 
25
25
  if (fileFormat) {
26
- if (config.experimental) {
27
- save.saveFile(
26
+ if (config.legacy === false) {
27
+ const sbomResponse = await sbom.generateSCASbom(
28
28
  config,
29
29
  fileFormat,
30
- await sbom.generateSCASbom(config, fileFormat, reportId)
30
+ reportId
31
31
  )
32
+ if (sbomResponse) {
33
+ save.saveFile(config, fileFormat, sbomResponse)
34
+ }
32
35
  } else {
33
- save.saveFile(
34
- config,
35
- fileFormat,
36
- await sbom.generateSbom(config, fileFormat)
37
- )
36
+ const sbomResponse = await sbom.generateSbom(config, fileFormat)
37
+ if (sbomResponse) {
38
+ save.saveFile(config, fileFormat, sbomResponse)
39
+ }
38
40
  }
39
41
  const filename = `${config.applicationId}-sbom-${fileFormat}.json`
40
42
  if (fs.existsSync(filename)) {
@@ -42,7 +44,7 @@ async function auditSave(config, reportId) {
42
44
  } else {
43
45
  console.log(
44
46
  chalk.yellow.bold(
45
- `\n Unable to save ${filename} Software Bill of Materials (SBOM)`
47
+ `\nUnable to save ${filename} Software Bill of Materials (SBOM)`
46
48
  )
47
49
  )
48
50
  }
@@ -51,7 +51,6 @@ const auditUsageGuide = commandLineUsage([
51
51
  'code',
52
52
  'maven-settings-path',
53
53
  'language',
54
- 'experimental',
55
54
  'app-groups',
56
55
  'metadata',
57
56
  'track',
@@ -10,11 +10,8 @@ const processAudit = async (contrastConf, argvMain) => {
10
10
  process.exit(0)
11
11
  }
12
12
 
13
- const config = await auditConfig.getAuditConfig(
14
- contrastConf,
15
- 'audit',
16
- argvMain
17
- )
13
+ let config = await auditConfig.getAuditConfig(contrastConf, 'audit', argvMain)
14
+
18
15
  await scaController.processSca(config)
19
16
  if (!config.fingerprint) {
20
17
  postRunMessage('audit')
@@ -14,7 +14,7 @@ const HIGH = 'HIGH'
14
14
  const CRITICAL = 'CRITICAL'
15
15
  // App
16
16
  const APP_NAME = 'contrast'
17
- const APP_VERSION = '1.0.22'
17
+ const APP_VERSION = '1.0.23'
18
18
  const TIMEOUT = 120000
19
19
  const HIGH_COLOUR = '#ff9900'
20
20
  const CRITICAL_COLOUR = '#e35858'
@@ -7,8 +7,15 @@ export const generateSbom = (config: any, type: string) => {
7
7
  .then((res: { statusCode: number; body: any }) => {
8
8
  if (res.statusCode === 200) {
9
9
  return res.body
10
+ } else if (res.statusCode === 403) {
11
+ console.log('\nUnable to retrieve Software Bill of Materials (SBOM)')
12
+ console.log(
13
+ `Please ensure OSS is enabled for your organization - org-id ${config.organizationId} and app ${config.applicationId}`
14
+ )
15
+ return undefined
10
16
  } else {
11
17
  console.log('Unable to retrieve Software Bill of Materials (SBOM)')
18
+ return undefined
12
19
  }
13
20
  })
14
21
  .catch((err: any) => {
@@ -29,6 +36,7 @@ export const generateSCASbom = (
29
36
  return res.body
30
37
  } else {
31
38
  console.log('Unable to retrieve Software Bill of Materials (SBOM)')
39
+ return undefined
32
40
  }
33
41
  })
34
42
  .catch((err: any) => {
@@ -217,9 +217,9 @@ function getIssueRow(cveArray) {
217
217
  }
218
218
 
219
219
  function getAdviceRow(advice) {
220
- const latestOrClosest = advice.latestStableVersion
221
- ? advice.latestStableVersion
222
- : advice.closestStableVersion
220
+ const latestOrClosest = advice.closestStableVersion
221
+ ? advice.closestStableVersion
222
+ : advice.latestStableVersion
223
223
  const displayAdvice = latestOrClosest
224
224
  ? `Change to version ${chalk.bold(latestOrClosest)}`
225
225
  : 'No recommendation is available according to our data. Upgrade to the latest stable is the best advice we can give.'
@@ -3,13 +3,11 @@ const { APP_VERSION } = require('../../constants/constants')
3
3
 
4
4
  const commonSendSnapShot = async (analysis, config) => {
5
5
  let requestBody = {}
6
- config.experimental === true
7
- ? (requestBody = sendToSCAServices(config, analysis))
8
- : (requestBody = {
9
- appID: config.applicationId,
10
- cliVersion: APP_VERSION,
11
- snapshot: analysis
12
- })
6
+ requestBody = {
7
+ appID: config.applicationId,
8
+ cliVersion: APP_VERSION,
9
+ snapshot: analysis
10
+ }
13
11
 
14
12
  const client = commonApi.getHttpClient(config)
15
13
  return client
@@ -33,19 +31,6 @@ const commonSendSnapShot = async (analysis, config) => {
33
31
  })
34
32
  }
35
33
 
36
- const sendToSCAServices = (config, analysis) => {
37
- return {
38
- applicationId: config.applicationId,
39
- dependencyTree: analysis,
40
- organizationId: config.organizationId,
41
- language: config.language,
42
- tool: {
43
- name: 'Contrast Codesec',
44
- version: APP_VERSION
45
- }
46
- }
47
- }
48
-
49
34
  module.exports = {
50
35
  commonSendSnapShot
51
36
  }
@@ -10,12 +10,7 @@ const goAnalysis = config => {
10
10
  const rawGoDependencies = goReadDepFile.getGoDependencies(config)
11
11
  const parsedGoDependencies =
12
12
  goParseDeps.parseGoDependencies(rawGoDependencies)
13
-
14
- if (config.experimental) {
15
- return parseDependenciesForSCAServices(parsedGoDependencies)
16
- } else {
17
- return createGoTSMessage(parsedGoDependencies)
18
- }
13
+ return createGoTSMessage(parsedGoDependencies)
19
14
  } catch (e) {
20
15
  console.log(e.message.toString())
21
16
  }
@@ -3,8 +3,6 @@ const spawn = require('cross-spawn')
3
3
  const path = require('path')
4
4
  const i18n = require('i18n')
5
5
  const fs = require('fs')
6
- const readLine = require('readline')
7
- const paramHandler = require('../../utils/paramsUtil/paramHandler')
8
6
 
9
7
  const MAVEN = 'maven'
10
8
  const GRADLE = 'gradle'
@@ -31,30 +29,31 @@ const determineProjectTypeAndCwd = (files, config) => {
31
29
  }
32
30
 
33
31
  const buildMaven = (config, projectData, timeout) => {
34
- let cmdStdout
35
- try {
36
- let command = 'mvn'
37
- let args = ['dependency:tree', '-B']
38
- if (config.mavenSettingsPath) {
39
- args.push('-s')
40
- args.push(config.mavenSettingsPath)
41
- }
42
- // Allow users to provide a custom location for their settings.xml
32
+ let command = 'mvn'
33
+ let args = ['dependency:tree', '-B']
34
+ if (config.mavenSettingsPath) {
35
+ args.push('-s')
36
+ args.push(config.mavenSettingsPath)
37
+ }
43
38
 
44
- cmdStdout = spawn
45
- .sync(command, args, {
46
- env: process.env,
47
- cwd: projectData.cwd,
48
- timeout
49
- })
50
- .stdout.toString()
39
+ // Allow users to provide a custom location for their settings.xml
40
+ const cmdDepTree = spawn.sync(command, args, {
41
+ env: process.env,
42
+ cwd: projectData.cwd,
43
+ timeout
44
+ })
51
45
 
52
- return cmdStdout.toString()
53
- } catch (err) {
54
- throw new Error(
55
- i18n.__('mavenDependencyTreeNonZero', projectData.cwd, `${err.message}`)
56
- )
46
+ if (cmdDepTree.status !== 0) {
47
+ //if maven not found
48
+ if (config.debug && cmdDepTree.error.code === 'ENOENT') {
49
+ console.log(`ERROR: mvn not found`)
50
+ console.log('Please make sure mvn is installed and accessible')
51
+ }
52
+
53
+ throw new Error(i18n.__('mavenDependencyTreeNonZero', projectData.cwd))
57
54
  }
55
+
56
+ return cmdDepTree.stdout.toString()
58
57
  }
59
58
 
60
59
  const buildGradle = (config, projectData, timeout) => {
@@ -133,18 +132,14 @@ const getJavaBuildDeps = (config, files) => {
133
132
  projectType: undefined
134
133
  }
135
134
 
136
- try {
137
- const projectData = determineProjectTypeAndCwd(files, config)
138
- if (projectData.projectType === MAVEN) {
139
- output.mvnDependancyTreeOutput = buildMaven(config, projectData, timeout)
140
- } else if (projectData.projectType === GRADLE) {
141
- output.mvnDependancyTreeOutput = buildGradle(config, projectData, timeout)
142
- }
143
- output.projectType = projectData.projectType
144
- return output
145
- } catch (err) {
146
- console.log(err.message.toString())
135
+ const projectData = determineProjectTypeAndCwd(files, config)
136
+ if (projectData.projectType === MAVEN) {
137
+ output.mvnDependancyTreeOutput = buildMaven(config, projectData, timeout)
138
+ } else if (projectData.projectType === GRADLE) {
139
+ output.mvnDependancyTreeOutput = buildGradle(config, projectData, timeout)
147
140
  }
141
+ output.projectType = projectData.projectType
142
+ return output
148
143
  }
149
144
 
150
145
  module.exports = {
@@ -11,12 +11,7 @@ const javaAnalysis = async (config, languageFiles) => {
11
11
  })
12
12
 
13
13
  const javaDeps = buildJavaTree(config, languageFiles.JAVA)
14
-
15
- if (config.experimental) {
16
- return parseDependenciesForSCAServices(javaDeps)
17
- } else {
18
- return createJavaTSMessage(javaDeps)
19
- }
14
+ return createJavaTSMessage(javaDeps)
20
15
  }
21
16
 
22
17
  const buildJavaTree = (config, files) => {
@@ -14,11 +14,6 @@ const jsAnalysis = async (config, languageFiles) => {
14
14
  const buildNodeTree = async (config, files) => {
15
15
  let analysis = await readFiles(config, files)
16
16
  const rawNode = await parseFiles(config, files, analysis)
17
-
18
- if (config.experimental) {
19
- return scaServiceParser.parseJS(rawNode)
20
- }
21
-
22
17
  return formatMessage.createJavaScriptTSMessage(rawNode)
23
18
  }
24
19
 
@@ -65,7 +60,7 @@ const parseFiles = async (config, files, js) => {
65
60
  )
66
61
  }
67
62
 
68
- if (currentLockFileVersion === 3 && !config.experimental) {
63
+ if (currentLockFileVersion === 3) {
69
64
  throw new Error(
70
65
  `NPM lockfileVersion 3 is only supported when using the '-e' flag.`
71
66
  )
@@ -1,16 +1,10 @@
1
1
  const { readFile, parseProjectFiles } = require('./analysis')
2
2
  const { createPhpTSMessage } = require('../common/formatMessage')
3
- const { parsePHPLockFileForScaServices } = require('./phpNewServicesMapper')
4
3
 
5
4
  const phpAnalysis = config => {
6
5
  let analysis = readFiles(config)
7
-
8
- if (config.experimental) {
9
- return parsePHPLockFileForScaServices(analysis.rawLockFileContents)
10
- } else {
11
- const phpDep = parseProjectFiles(analysis)
12
- return createPhpTSMessage(phpDep)
13
- }
6
+ const phpDep = parseProjectFiles(analysis)
7
+ return createPhpTSMessage(phpDep)
14
8
  }
15
9
 
16
10
  const readFiles = config => {
@@ -60,16 +60,10 @@ const checkForCorrectFiles = languageFiles => {
60
60
 
61
61
  const getPythonDeps = (config, languageFiles) => {
62
62
  try {
63
- if (config.experimental) {
64
- let pythonLockFileContents = readLockFile(config.file)
65
- return scaPythonParser(pythonLockFileContents)
66
- } else {
67
- checkForCorrectFiles(languageFiles)
68
- const parseProject = readAndParseProjectFile(config.file)
69
- const parsePip = readAndParseLockFile(config.file)
70
-
71
- return { pipfileLock: parsePip, pipfilDependanceies: parseProject }
72
- }
63
+ checkForCorrectFiles(languageFiles)
64
+ const parseProject = readAndParseProjectFile(config.file)
65
+ const parsePip = readAndParseLockFile(config.file)
66
+ return { pipfileLock: parsePip, pipfilDependanceies: parseProject }
73
67
  } catch (err) {
74
68
  console.log(err.message.toString())
75
69
  process.exit(1)
@@ -3,12 +3,7 @@ const { getPythonDeps, secondaryParser } = require('./analysis')
3
3
 
4
4
  const pythonAnalysis = (config, languageFiles) => {
5
5
  const pythonDeps = getPythonDeps(config, languageFiles.PYTHON)
6
-
7
- if (config.experimental) {
8
- return pythonDeps
9
- } else {
10
- return createPythonTSMessage(pythonDeps)
11
- }
6
+ return createPythonTSMessage(pythonDeps)
12
7
  }
13
8
 
14
9
  module.exports = {
@@ -6,17 +6,7 @@ const getRubyDeps = (config, languageFiles) => {
6
6
  checkForCorrectFiles(languageFiles)
7
7
  const parsedGem = readAndParseGemfile(config.file)
8
8
  const parsedLock = readAndParseGemLockFile(config.file)
9
- if (config.experimental) {
10
- const rubyArray = removeRedundantAndPopulateDefinedElements(
11
- parsedLock.sources
12
- )
13
- let rubyTree = createRubyTree(rubyArray)
14
- findChildrenDependencies(rubyTree)
15
- processRootDependencies(parsedLock.dependencies, rubyTree)
16
- return rubyTree
17
- } else {
18
- return { gemfilesDependanceies: parsedGem, gemfileLock: parsedLock }
19
- }
9
+ return { gemfilesDependanceies: parsedGem, gemfileLock: parsedLock }
20
10
  } catch (err) {
21
11
  throw err
22
12
  }
@@ -3,12 +3,7 @@ const { createRubyTSMessage } = require('../common/formatMessage')
3
3
 
4
4
  const rubyAnalysis = (config, languageFiles) => {
5
5
  const rubyDeps = analysis.getRubyDeps(config, languageFiles.RUBY)
6
-
7
- if (config.experimental) {
8
- return rubyDeps
9
- } else {
10
- return createRubyTSMessage(rubyDeps)
11
- }
6
+ return createRubyTSMessage(rubyDeps)
12
7
  }
13
8
 
14
9
  module.exports = {
@@ -26,18 +26,10 @@ const { rubyAnalysis } = require('./ruby')
26
26
  const { pythonAnalysis } = require('./python')
27
27
  const javaAnalysis = require('./java')
28
28
  const jsAnalysis = require('./javascript')
29
- const auditReport = require('./common/auditReport')
30
- const scaUpload = require('./common/scaServicesUpload')
31
- const settingsHelper = require('../utils/settingsHelper')
32
29
  const chalk = require('chalk')
33
- const saveResults = require('../scan/saveResults')
34
- const {
35
- convertGenericToTypedReportModelSca
36
- } = require('./common/utils/reportUtilsSca')
37
30
 
38
31
  const processSca = async config => {
39
32
  //checks to see whether to use old TS / new SCA path
40
- config = await settingsHelper.getSettings(config)
41
33
 
42
34
  const startTime = performance.now()
43
35
  let filesFound
@@ -72,18 +64,7 @@ const processSca = async config => {
72
64
  switch (Object.keys(filesFound[0])[0]) {
73
65
  case JAVA:
74
66
  config.language = JAVA
75
-
76
- if (config.mode === 'repo') {
77
- try {
78
- return repoMode.buildRepo(config, filesFound[0])
79
- } catch (e) {
80
- throw new Error(
81
- 'Unable to build in repository mode. Check your project file'
82
- )
83
- }
84
- } else {
85
- messageToSend = await javaAnalysis.javaAnalysis(config, filesFound[0])
86
- }
67
+ messageToSend = await javaAnalysis.javaAnalysis(config, filesFound[0])
87
68
  break
88
69
  case JAVASCRIPT:
89
70
  messageToSend = await jsAnalysis.jsAnalysis(config, filesFound[0])
@@ -106,18 +87,9 @@ const processSca = async config => {
106
87
  config.language = GO
107
88
  break
108
89
  case DOTNET:
109
- if (config.experimental) {
110
- console.log(
111
- `${chalk.bold(
112
- '\n.NET project found\n'
113
- )} Language type is unsupported.`
114
- )
115
- return
116
- } else {
117
- messageToSend = dotNetAnalysis(config, filesFound[0])
118
- config.language = DOTNET
119
- break
120
- }
90
+ messageToSend = dotNetAnalysis(config, filesFound[0])
91
+ config.language = DOTNET
92
+ break
121
93
  default:
122
94
  //something is wrong
123
95
  console.log('No supported language detected in project path')
@@ -127,63 +99,31 @@ const processSca = async config => {
127
99
  if (!config.applicationId) {
128
100
  config.applicationId = await auditController.dealWithNoAppId(config)
129
101
  }
102
+ console.log('') //empty log for space before spinner
103
+ //send message to TS
104
+ const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'))
105
+ startSpinner(reportSpinner)
106
+ const snapshotResponse = await treeUpload.commonSendSnapShot(
107
+ messageToSend,
108
+ config
109
+ )
130
110
 
131
- if (config.experimental) {
132
- console.log('') //empty log for space before spinner
133
- const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'))
134
- startSpinner(reportSpinner)
135
- const { reportArray, reportId } = await scaUpload.scaTreeUpload(
136
- messageToSend,
137
- config
138
- )
139
-
140
- const reportModelLibraryList =
141
- convertGenericToTypedReportModelSca(reportArray)
142
- auditReport.processAuditReport(config, reportModelLibraryList)
143
- succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'))
144
-
145
- if (config.save !== undefined) {
146
- await auditSave.auditSave(config, reportId)
147
- } else {
148
- console.log('Use contrast audit --save to generate an SBOM')
149
- }
111
+ // poll for completion
112
+ await pollForSnapshotCompletion(config, snapshotResponse.id, reportSpinner)
113
+ succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'))
150
114
 
151
- const endTime = performance.now() - startTime
152
- const scanDurationMs = endTime - startTime
153
- console.log(
154
- `----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`
155
- )
115
+ await vulnerabilityReportV2(config, snapshotResponse.id)
116
+ if (config.save !== undefined) {
117
+ await auditSave.auditSave(config)
156
118
  } else {
157
- console.log('') //empty log for space before spinner
158
- //send message to TS
159
- const reportSpinner = returnOra(i18n.__('auditSCAAnalysisBegins'))
160
- startSpinner(reportSpinner)
161
- const snapshotResponse = await treeUpload.commonSendSnapShot(
162
- messageToSend,
163
- config
164
- )
165
-
166
- // poll for completion
167
- await pollForSnapshotCompletion(
168
- config,
169
- snapshotResponse.id,
170
- reportSpinner
171
- )
172
- succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'))
173
-
174
- await vulnerabilityReportV2(config, snapshotResponse.id)
175
- if (config.save !== undefined) {
176
- await auditSave.auditSave(config)
177
- } else {
178
- console.log('\nUse contrast audit --save to generate an SBOM')
179
- }
180
- const endTime = performance.now() - startTime
181
- const scanDurationMs = endTime - startTime
182
-
183
- console.log(
184
- `----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`
185
- )
119
+ console.log('\nUse contrast audit --save to generate an SBOM')
186
120
  }
121
+ const endTime = performance.now() - startTime
122
+ const scanDurationMs = endTime - startTime
123
+
124
+ console.log(
125
+ `----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`
126
+ )
187
127
  } else {
188
128
  if (filesFound.length === 0) {
189
129
  console.log(i18n.__('languageAnalysisNoLanguage'))
@@ -1,24 +0,0 @@
1
- "use strict";
2
- const commonApi = require('./commonApi');
3
- const { getMode } = require('./generalAPI');
4
- const { SAAS, MODE_BUILD } = require('../constants/constants');
5
- const getSettings = async (config) => {
6
- config.isEOP = (await getMode(config)).toUpperCase() === SAAS ? false : true;
7
- config.mode = MODE_BUILD;
8
- config.scaServices = await isSCAServicesAvailable(config);
9
- return config;
10
- };
11
- const isSCAServicesAvailable = async (config) => {
12
- const client = commonApi.getHttpClient(config);
13
- return client
14
- .scaServiceHealth(config)
15
- .then(res => {
16
- return res.body.status === 'UP';
17
- })
18
- .catch(err => {
19
- console.log(err);
20
- });
21
- };
22
- module.exports = {
23
- getSettings
24
- };
@@ -1,26 +0,0 @@
1
- const commonApi = require('./commonApi')
2
- const { getMode } = require('./generalAPI')
3
- const { SAAS, MODE_BUILD } = require('../constants/constants')
4
-
5
- const getSettings = async config => {
6
- config.isEOP = (await getMode(config)).toUpperCase() === SAAS ? false : true
7
- config.mode = MODE_BUILD
8
- config.scaServices = await isSCAServicesAvailable(config)
9
- return config
10
- }
11
-
12
- const isSCAServicesAvailable = async config => {
13
- const client = commonApi.getHttpClient(config)
14
- return client
15
- .scaServiceHealth(config)
16
- .then(res => {
17
- return res.body.status === 'UP'
18
- })
19
- .catch(err => {
20
- console.log(err)
21
- })
22
- }
23
-
24
- module.exports = {
25
- getSettings
26
- }