@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.
- package/dist/audit/autodetection/autoDetectLanguage.js +3 -3
- package/dist/audit/catalogueApplication/catalogueApplication.js +23 -5
- package/dist/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +5 -5
- package/dist/audit/languageAnalysisEngine/getProjectRootFilenames.js +9 -9
- package/dist/audit/languageAnalysisEngine/index.js +2 -2
- package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +5 -28
- package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +11 -4
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +39 -13
- package/dist/audit/languageAnalysisEngine/report/models/reportListModel.js +2 -1
- package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +3 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +35 -14
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +3 -3
- package/dist/audit/save.js +29 -0
- package/dist/commands/audit/auditController.js +21 -5
- package/dist/commands/audit/help.js +24 -1
- package/dist/commands/audit/processAudit.js +7 -1
- package/dist/commands/audit/saveFile.js +7 -3
- package/dist/commands/scan/sca/scaAnalysis.js +31 -10
- package/dist/common/HTTPClient.js +6 -0
- package/dist/common/versionChecker.js +19 -4
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +12 -11
- package/dist/constants.js +9 -4
- package/dist/index.js +4 -3
- package/dist/sbom/generateSbom.js +4 -3
- package/dist/scaAnalysis/common/formatMessage.js +26 -5
- package/dist/scaAnalysis/common/treeUpload.js +0 -1
- package/dist/scaAnalysis/go/goReadDepFile.js +1 -3
- package/dist/scaAnalysis/java/analysis.js +5 -5
- package/dist/scaAnalysis/javascript/analysis.js +110 -0
- package/dist/scaAnalysis/javascript/index.js +41 -0
- package/dist/scaAnalysis/php/analysis.js +89 -0
- package/dist/scaAnalysis/php/index.js +10 -0
- package/dist/scaAnalysis/python/analysis.js +8 -7
- package/dist/scaAnalysis/ruby/analysis.js +8 -8
- package/dist/scaAnalysis/ruby/index.js +2 -2
- package/dist/scan/autoDetection.js +4 -4
- package/dist/scan/fileUtils.js +13 -2
- package/dist/utils/filterProjectPath.js +7 -2
- package/package.json +3 -3
- package/src/audit/autodetection/autoDetectLanguage.ts +3 -3
- package/src/audit/catalogueApplication/catalogueApplication.js +28 -6
- package/src/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +5 -5
- package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +11 -11
- package/src/audit/languageAnalysisEngine/index.js +2 -2
- package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +4 -32
- package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +20 -19
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +67 -17
- package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +4 -1
- package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +4 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +49 -17
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +1 -1
- package/src/audit/save.js +32 -0
- package/src/commands/audit/auditController.ts +22 -13
- package/src/commands/audit/help.ts +24 -1
- package/src/commands/audit/processAudit.ts +6 -3
- package/src/commands/audit/saveFile.ts +5 -1
- package/src/commands/scan/sca/scaAnalysis.js +53 -22
- package/src/common/HTTPClient.js +7 -0
- package/src/common/versionChecker.ts +23 -4
- package/src/constants/constants.js +1 -1
- package/src/constants/locales.js +12 -11
- package/src/constants.js +9 -4
- package/src/index.ts +5 -3
- package/src/sbom/generateSbom.ts +1 -1
- package/src/scaAnalysis/common/formatMessage.js +27 -5
- package/src/scaAnalysis/common/treeUpload.js +0 -1
- package/src/scaAnalysis/go/goReadDepFile.js +1 -3
- package/src/scaAnalysis/java/analysis.js +5 -5
- package/src/scaAnalysis/javascript/analysis.js +127 -0
- package/src/scaAnalysis/javascript/index.js +56 -0
- package/src/scaAnalysis/php/analysis.js +98 -0
- package/src/scaAnalysis/php/index.js +11 -0
- package/src/scaAnalysis/python/analysis.js +8 -7
- package/src/scaAnalysis/ruby/analysis.js +8 -8
- package/src/scaAnalysis/ruby/index.js +2 -2
- package/src/scan/autoDetection.js +4 -4
- package/src/scan/fileUtils.js +13 -2
- 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,
|
|
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.
|
|
14
|
-
|
|
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.
|
|
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
|
|
28
|
-
messageToSend =
|
|
29
|
-
config.language =
|
|
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
|
-
|
|
47
|
-
|
|
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 --
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
|
94
|
-
failOptionErrorMessage:
|
|
95
|
-
constantsSeverity: '
|
|
96
|
-
constantsCount:
|
|
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: '
|
|
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
|
|
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: '
|
|
283
|
+
scanNoVulnerabilitiesFound: '🎉 No vulnerabilities found.',
|
|
284
284
|
scanNoVulnerabilitiesFoundSecureCode: '👍 Your code looks secure.',
|
|
285
|
-
scanNoVulnerabilitiesFoundGoodWork: '
|
|
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
|
|
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: '
|
|
192
|
-
|
|
190
|
+
name: 'file',
|
|
191
|
+
alias: 'f',
|
|
192
|
+
defaultValue: process.cwd(),
|
|
193
193
|
description: '{bold ' +
|
|
194
194
|
i18n.__('constantsOptional') +
|
|
195
195
|
'}: ' +
|
|
196
|
-
i18n.__('
|
|
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
|
|
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') >=
|
|
44
|
-
await (0, versionChecker_1.findLatestCLIVersion)(config
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
};
|
|
@@ -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.
|
|
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,
|
|
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 =
|
|
17
|
-
?
|
|
18
|
-
:
|
|
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.
|
|
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
|
+
};
|