From 3a0c63562fbc3240efb20d1aa6c8f195c0b64f4e Mon Sep 17 00:00:00 2001 From: Ilona Shishov Date: Thu, 14 Mar 2024 14:06:01 +0200 Subject: [PATCH] chore: add new settings for python and go ecosystems Signed-off-by: Ilona Shishov --- package-lock.json | 22 +++++++++--------- package.json | 28 +++++++++++++++++++++-- src/caNotification.ts | 4 +++- src/config.ts | 16 +++++++++++++ src/constants.ts | 4 ++++ src/extension.ts | 11 +++++---- src/stackAnalysis.ts | 4 ++++ src/utils.ts | 14 ++++++++++++ test/config.test.ts | 8 +++++++ test/utils.test.ts | 53 +++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 146 insertions(+), 18 deletions(-) create mode 100644 src/utils.ts create mode 100644 test/utils.test.ts diff --git a/package-lock.json b/package-lock.json index 05ff5c9a0..408e69e86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,9 @@ "version": "0.9.4", "license": "Apache-2.0", "dependencies": { - "@fabric8-analytics/fabric8-analytics-lsp-server": "^0.9.4-ea.2", + "@fabric8-analytics/fabric8-analytics-lsp-server": "^0.9.4-ea.6", "@redhat-developer/vscode-redhat-telemetry": "^0.7.0", - "@RHEcosystemAppEng/exhort-javascript-api": "^0.1.1-ea.14", + "@RHEcosystemAppEng/exhort-javascript-api": "^0.1.1-ea.26", "fs": "^0.0.1-security", "path": "^0.12.7", "vscode-languageclient": "^8.1.0" @@ -82,11 +82,11 @@ }, "../fabric8-analytics-lsp-server": { "name": "@fabric8-analytics/fabric8-analytics-lsp-server", - "version": "0.9.4-ea.1", + "version": "0.9.4-ea.5", "extraneous": true, "license": "Apache-2.0", "dependencies": { - "@RHEcosystemAppEng/exhort-javascript-api": "^0.1.1-ea.14", + "@RHEcosystemAppEng/exhort-javascript-api": "^0.1.1-ea.26", "@xml-tools/ast": "^5.0.5", "@xml-tools/parser": "^1.0.11", "json-to-ast": "^2.1.0", @@ -568,12 +568,12 @@ } }, "node_modules/@fabric8-analytics/fabric8-analytics-lsp-server": { - "version": "0.9.4-ea.2", - "resolved": "https://npm.pkg.github.com/download/@fabric8-analytics/fabric8-analytics-lsp-server/0.9.4-ea.2/ca0ace6cc0f37bdf19993529aa18ce9094654801", - "integrity": "sha512-mdIiga72ISXBzAa0XNtwWLdMOjukGHZXDPpGABvP4E3NyTdfL9wGti3mV2S9oyU5wUy3LsWZBgkLXLDYrboBfA==", + "version": "0.9.4-ea.6", + "resolved": "https://npm.pkg.github.com/download/@fabric8-analytics/fabric8-analytics-lsp-server/0.9.4-ea.6/f43cb1fae9d5c3498d9825390d0f1009a23cfc12", + "integrity": "sha512-0syQBZtmhctHal8mlRdwonidfF54jstKWSl6C1GDSp7yqEUVm6Zgw3FO6VYZB0FZhTnscXLc3A4JOzN51+cM9w==", "license": "Apache-2.0", "dependencies": { - "@RHEcosystemAppEng/exhort-javascript-api": "^0.1.1-ea.14", + "@RHEcosystemAppEng/exhort-javascript-api": "^0.1.1-ea.26", "@xml-tools/ast": "^5.0.5", "@xml-tools/parser": "^1.0.11", "json-to-ast": "^2.1.0", @@ -950,9 +950,9 @@ } }, "node_modules/@RHEcosystemAppEng/exhort-javascript-api": { - "version": "0.1.1-ea.14", - "resolved": "https://npm.pkg.github.com/download/@RHEcosystemAppEng/exhort-javascript-api/0.1.1-ea.14/b7f01baf0e01d8d697a2b5264e4f374d001004fd", - "integrity": "sha512-B0bnokCaz37eS3dIQPuPuwrAGU/y3TM4DT8u7xMMN9hjK9kSOq4UsWPgkJIaYstUzChgomQnXTRQhd2kNfvIIw==", + "version": "0.1.1-ea.26", + "resolved": "https://npm.pkg.github.com/download/@RHEcosystemAppEng/exhort-javascript-api/0.1.1-ea.26/883fb514fb41a6e1f52e426e1ed1d9c8fae26eed", + "integrity": "sha512-2QORNJ4vrYWyIgKai09HQs+AM9s9JCuJffrGB6CT9OnY7L+I4LT+YN6iHIo0rvoaQR4MfQl4OmXfHij1HuQ8VQ==", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.23.2", diff --git a/package.json b/package.json index cbe8fea50..20c7c1a48 100644 --- a/package.json +++ b/package.json @@ -231,6 +231,30 @@ "default": "Error", "description": "Defines the severity level of alerts for detected vulnerabilities in dependencies.", "scope": "window" + }, + "redHatDependencyAnalytics.usePythonVirtualEnvironment": { + "type": "boolean", + "default": false, + "description": "Automates the installation of missing packages in a Python virtual environment.", + "scope": "window" + }, + "redHatDependencyAnalytics.useGoMVS": { + "type": "boolean", + "default": false, + "description": "Uses the Minimal version selection (MVS) algorithm to select a set of module versions to use when building Go packages.", + "scope": "window" + }, + "redHatDependencyAnalytics.enablePythonBestEffortsInstallation": { + "type": "boolean", + "default": false, + "description": "Installs Python packages tailored to the Python version in use, disregarding declared versions. Note: Requires settings Match Manifest Versions to be set to false and Use Python Virtual Environment to be set to true.", + "scope": "window" + }, + "redHatDependencyAnalytics.usePipDepTree": { + "type": "boolean", + "default": false, + "description": "Use lightweight pipdeptree command line tool as the data source for building the Python dependency tree. This may significantly enhance analysis time.", + "scope": "window" } } } @@ -273,9 +297,9 @@ "webpack-cli": "^5.1.4" }, "dependencies": { - "@fabric8-analytics/fabric8-analytics-lsp-server": "^0.9.4-ea.2", + "@fabric8-analytics/fabric8-analytics-lsp-server": "^0.9.4-ea.6", "@redhat-developer/vscode-redhat-telemetry": "^0.7.0", - "@RHEcosystemAppEng/exhort-javascript-api": "^0.1.1-ea.14", + "@RHEcosystemAppEng/exhort-javascript-api": "^0.1.1-ea.26", "fs": "^0.0.1-security", "path": "^0.12.7", "vscode-languageclient": "^8.1.0" diff --git a/src/caNotification.ts b/src/caNotification.ts index 792c5136e..fca716add 100644 --- a/src/caNotification.ts +++ b/src/caNotification.ts @@ -1,5 +1,7 @@ 'use strict'; +import { applySettingNameMappings } from './utils'; + /** * Interface representing the data structure for a Component Analysis (CA) Notification. */ @@ -35,7 +37,7 @@ class CANotification { * @param respData The data used to create the notification. */ constructor(respData: CANotificationData) { - this.errorMessage = respData.errorMessage || ''; + this.errorMessage = applySettingNameMappings(respData.errorMessage || ''); this.done = respData.done === true; this.uri = respData.uri; this.diagCount = respData.diagCount || 0; diff --git a/src/config.ts b/src/config.ts index 351b89c2b..8f7e5247f 100644 --- a/src/config.ts +++ b/src/config.ts @@ -15,6 +15,10 @@ class Config { rhRepositoryRecommendationNotificationCommand: string; utmSource: string; matchManifestVersions: string; + usePythonVirtualEnvironment: string; + useGoMVS: string; + enablePythonBestEffortsInstallation: string; + usePipDepTree: string; vulnerabilityAlertSeverity: string; exhortMvnPath: string; exhortNpmPath: string; @@ -62,6 +66,14 @@ class Config { this.utmSource = GlobalState.UTM_SOURCE; /* istanbul ignore next */ this.matchManifestVersions = rhdaConfig.matchManifestVersions ? 'true' : 'false'; + /* istanbul ignore next */ + this.usePythonVirtualEnvironment = rhdaConfig.usePythonVirtualEnvironment ? 'true' : 'false'; + /* istanbul ignore next */ + this.useGoMVS = rhdaConfig.useGoMVS ? 'true' : 'false'; + /* istanbul ignore next */ + this.enablePythonBestEffortsInstallation = rhdaConfig.enablePythonBestEffortsInstallation ? 'true' : 'false'; + /* istanbul ignore next */ + this.usePipDepTree = rhdaConfig.usePipDepTree ? 'true' : 'false'; this.vulnerabilityAlertSeverity = rhdaConfig.vulnerabilityAlertSeverity; /* istanbul ignore next */ this.rhdaReportFilePath = rhdaConfig.reportFilePath || DEFAULT_RHDA_REPORT_FILE_PATH; @@ -83,6 +95,10 @@ class Config { process.env['VSCEXT_REDHAT_REPOSITORY_RECOMMENDATION_NOTIFICATION_COMMAND'] = this.rhRepositoryRecommendationNotificationCommand; process.env['VSCEXT_UTM_SOURCE'] = this.utmSource; process.env['VSCEXT_MATCH_MANIFEST_VERSIONS'] = this.matchManifestVersions; + process.env['VSCEXT_USE_PYTHON_VIRTUAL_ENVIRONMENT'] = this.usePythonVirtualEnvironment; + process.env['VSCEXT_USE_GO_MVS'] = this.useGoMVS; + process.env['VSCEXT_ENABLE_PYTHON_BEST_EFFORTS_INSTALLATION'] = this.enablePythonBestEffortsInstallation; + process.env['VSCEXT_USE_PIP_DEP_TREE'] = this.usePipDepTree; process.env['VSCEXT_VULNERABILITY_ALERT_SEVERITY'] = this.vulnerabilityAlertSeverity; process.env['VSCEXT_EXHORT_MVN_PATH'] = this.exhortMvnPath; process.env['VSCEXT_EXHORT_NPM_PATH'] = this.exhortNpmPath; diff --git a/src/constants.ts b/src/constants.ts index c38131913..11e22d228 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -28,6 +28,10 @@ export enum Titles { REPORT_TITLE = `Red Hat Dependency Analytics Report`, } +export const settingNameMappings: { [key: string]: string } = { + 'EXHORT_PYTHON_VIRTUAL_ENV': 'Use Python Virtual Environment' +}; + // Refer `name` from package.json export const EXTENSION_ID = 'fabric8-analytics'; // publisher.name from package.json diff --git a/src/extension.ts b/src/extension.ts index 17094a173..48cb68200 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -19,6 +19,7 @@ import { CANotification } from './caNotification'; import { DepOutputChannel } from './depOutputChannel'; import { record, startUp, TelemetryActions } from './redhatTelemetry'; // import { validateSnykToken } from './tokenValidation'; +import { applySettingNameMappings } from './utils'; let lspClient: LanguageClient; @@ -45,8 +46,9 @@ export function activate(context: vscode.ExtensionContext) { await generateRHDAReport(context, fileUri); record(context, TelemetryActions.vulnerabilityReportDone, { manifest: path.basename(fileUri.fsPath), fileName: path.basename(fileUri.fsPath) }); } catch (error) { - vscode.window.showErrorMessage(error.message); - record(context, TelemetryActions.vulnerabilityReportFailed, { manifest: path.basename(fileUri.fsPath), fileName: path.basename(fileUri.fsPath), error: error.message }); + const message = applySettingNameMappings(error.message); + vscode.window.showErrorMessage(message); + record(context, TelemetryActions.vulnerabilityReportFailed, { manifest: path.basename(fileUri.fsPath), fileName: path.basename(fileUri.fsPath), error: message }); } } ); @@ -251,8 +253,9 @@ function registerStackAnalysisCommands(context: vscode.ExtensionContext) { await generateRHDAReport(context, uri); record(context, TelemetryActions.vulnerabilityReportDone, { manifest: path.basename(uri.fsPath), fileName: path.basename(uri.fsPath) }); } catch (error) { - vscode.window.showErrorMessage(error.message); - record(context, TelemetryActions.vulnerabilityReportFailed, { manifest: path.basename(uri.fsPath), fileName: path.basename(uri.fsPath), error: error.message }); + const message = applySettingNameMappings(error.message); + vscode.window.showErrorMessage(message); + record(context, TelemetryActions.vulnerabilityReportFailed, { manifest: path.basename(uri.fsPath), fileName: path.basename(uri.fsPath), error: message }); } }; diff --git a/src/stackAnalysis.ts b/src/stackAnalysis.ts index f1fc3d991..b14106e32 100644 --- a/src/stackAnalysis.ts +++ b/src/stackAnalysis.ts @@ -69,6 +69,10 @@ async function executeStackAnalysis(manifestFilePath): Promise { 'RHDA_TOKEN': globalConfig.telemetryId, 'RHDA_SOURCE': globalConfig.utmSource, 'MATCH_MANIFEST_VERSIONS': globalConfig.matchManifestVersions, + 'EXHORT_PYTHON_VIRTUAL_ENV': globalConfig.usePythonVirtualEnvironment, + 'EXHORT_GO_MVS_LOGIC_ENABLED': globalConfig.useGoMVS, + 'EXHORT_PYTHON_INSTALL_BEST_EFFORTS': globalConfig.enablePythonBestEffortsInstallation, + 'EXHORT_PIP_USE_DEP_TREE': globalConfig.usePipDepTree, 'EXHORT_MVN_PATH': globalConfig.exhortMvnPath, 'EXHORT_NPM_PATH': globalConfig.exhortNpmPath, 'EXHORT_GO_PATH': globalConfig.exhortGoPath, diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 000000000..2bfbc9b7c --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,14 @@ +'use strict'; + +import { settingNameMappings } from './constants'; + +export function applySettingNameMappings(message: string): string { + let modifiedMessage = message; + + Object.keys(settingNameMappings).forEach(key => { + const regex = new RegExp(key, 'g'); + modifiedMessage = modifiedMessage.replace(regex, settingNameMappings[key]); + }); + + return modifiedMessage; +} \ No newline at end of file diff --git a/test/config.test.ts b/test/config.test.ts index 08837a8f7..617370d10 100644 --- a/test/config.test.ts +++ b/test/config.test.ts @@ -33,6 +33,10 @@ suite('Config module', () => { expect(globalConfig.rhRepositoryRecommendationNotificationCommand).to.eq(commands.REDHAT_REPOSITORY_RECOMMENDATION_NOTIFICATION_COMMAND); expect(globalConfig.utmSource).to.eq(GlobalState.UTM_SOURCE); expect(globalConfig.matchManifestVersions).to.eq('true'); + expect(globalConfig.usePythonVirtualEnvironment).to.eq('false'); + expect(globalConfig.useGoMVS).to.eq('false'); + expect(globalConfig.enablePythonBestEffortsInstallation).to.eq('false'); + expect(globalConfig.usePipDepTree).to.eq('false'); expect(globalConfig.vulnerabilityAlertSeverity).to.eq('Error'); expect(globalConfig.rhdaReportFilePath).to.eq('/tmp/redhatDependencyAnalyticsReport.html'); expect(globalConfig.exhortMvnPath).to.eq('mvn'); @@ -63,6 +67,10 @@ suite('Config module', () => { expect(process.env['VSCEXT_REDHAT_REPOSITORY_RECOMMENDATION_NOTIFICATION_COMMAND']).to.eq(commands.REDHAT_REPOSITORY_RECOMMENDATION_NOTIFICATION_COMMAND); expect(process.env['VSCEXT_UTM_SOURCE']).to.eq(GlobalState.UTM_SOURCE); expect(process.env['VSCEXT_MATCH_MANIFEST_VERSIONS']).to.eq('true'); + expect(process.env['VSCEXT_USE_PYTHON_VIRTUAL_ENVIRONMENT']).to.eq('false'); + expect(process.env['VSCEXT_USE_GO_MVS']).to.eq('false'); + expect(process.env['VSCEXT_ENABLE_PYTHON_BEST_EFFORTS_INSTALLATION']).to.eq('false'); + expect(process.env['VSCEXT_USE_PIP_DEP_TREE']).to.eq('false'); expect(process.env['VSCEXT_VULNERABILITY_ALERT_SEVERITY']).to.eq('Error'); expect(process.env['VSCEXT_EXHORT_MVN_PATH']).to.eq('mvn'); expect(process.env['VSCEXT_EXHORT_NPM_PATH']).to.eq('npm'); diff --git a/test/utils.test.ts b/test/utils.test.ts new file mode 100644 index 000000000..5afec4a8e --- /dev/null +++ b/test/utils.test.ts @@ -0,0 +1,53 @@ +import * as chai from 'chai'; +import * as sinon from 'sinon'; +import * as sinonChai from 'sinon-chai'; + +import { settingNameMappings } from '../src/constants'; +import { applySettingNameMappings } from '../src/utils'; + +const expect = chai.expect; +chai.use(sinonChai); + +suite('Utils module', () => { + let sandbox: sinon.SinonSandbox; + + setup(() => { + sandbox = sinon.createSandbox(); + }); + + teardown(() => { + sandbox.restore(); + }); + + test('should return a string with applied mappings', () => { + + Object.keys(settingNameMappings).forEach(key => { + const message = `The ${key} variable should be set.`; + const expectedMessage = `The ${settingNameMappings[key]} variable should be set.`; + + const result = applySettingNameMappings(message); + + expect(result).to.equal(expectedMessage); + }); + }); + + test('should handle multiple occurrences of mapping keys', () => { + + Object.keys(settingNameMappings).forEach(key => { + const message = `Please ensure the ${key} is properly configured. Set ${key} to true.`; + const expectedMessage = `Please ensure the ${settingNameMappings[key]} is properly configured. Set ${settingNameMappings[key]} to true.`; + + const result = applySettingNameMappings(message); + + expect(result).to.equal(expectedMessage); + }); + }); + + test('should not modify the message if no mappings apply', () => { + const message = 'This message does not contain any mapping keys.'; + + const result = applySettingNameMappings(message); + + expect(result).to.equal(message); + }); +});