Skip to content

Commit

Permalink
chore: integrate secret storage (#689)
Browse files Browse the repository at this point in the history
* feat: save RHDA Snyk Token configuration in VSCode Secret Storage

Signed-off-by: Ilona Shishov <[email protected]>

* chore: updated the names of commands in the package.json file

Signed-off-by: Ilona Shishov <[email protected]>

* test: updated unit tests

Signed-off-by: Ilona Shishov <[email protected]>

---------

Signed-off-by: Ilona Shishov <[email protected]>
  • Loading branch information
IlonaShishov authored Feb 29, 2024
1 parent c81f447 commit 45116cc
Show file tree
Hide file tree
Showing 17 changed files with 364 additions and 161 deletions.
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 33 additions & 25 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,102 +48,107 @@
"contributes": {
"commands": [
{
"command": "fabric8.stackAnalysis",
"command": "rhda.stackAnalysis",
"title": "Red Hat Dependency Analytics Report...",
"category": "Red Hat Dependency Analytics"
},
{
"command": "fabric8.stackAnalysisFromPieBtn",
"command": "rhda.stackAnalysisFromPieBtn",
"title": "Open Red Hat Dependency Analytics Report",
"icon": {
"light": "icon/report-icon.png",
"dark": "icon/report-icon.png"
}
},
{
"command": "fabric8.stackAnalysisFromEditor",
"command": "rhda.stackAnalysisFromEditor",
"title": "Red Hat Dependency Analytics Report..."
},
{
"command": "fabric8.stackAnalysisFromExplorer",
"command": "rhda.stackAnalysisFromExplorer",
"title": "Red Hat Dependency Analytics Report..."
},
{
"command": "fabric8.fabric8AnalyticsStackLogs",
"command": "rhda.stackLogs",
"title": "Debug logs",
"category": "Red Hat Dependency Analytics"
},
{
"command": "rhda.setSnykToken",
"title": "Set Snyk Token",
"category": "Red Hat Dependency Analytics"
}
],
"menus": {
"editor/title": [
{
"command": "fabric8.stackAnalysisFromPieBtn",
"command": "rhda.stackAnalysisFromPieBtn",
"when": "resourceFilename == pom.xml",
"group": "navigation"
},
{
"command": "fabric8.stackAnalysisFromPieBtn",
"command": "rhda.stackAnalysisFromPieBtn",
"when": "resourceFilename == package.json",
"group": "navigation"
},
{
"command": "fabric8.stackAnalysisFromPieBtn",
"command": "rhda.stackAnalysisFromPieBtn",
"when": "resourceFilename == go.mod",
"group": "navigation"
},
{
"command": "fabric8.stackAnalysisFromPieBtn",
"command": "rhda.stackAnalysisFromPieBtn",
"when": "resourceFilename == requirements.txt",
"group": "navigation"
}
],
"explorer/context": [
{
"command": "fabric8.stackAnalysisFromExplorer",
"command": "rhda.stackAnalysisFromExplorer",
"when": "resourceFilename == package.json"
},
{
"command": "fabric8.stackAnalysisFromExplorer",
"command": "rhda.stackAnalysisFromExplorer",
"when": "resourceFilename == pom.xml"
},
{
"command": "fabric8.stackAnalysisFromExplorer",
"command": "rhda.stackAnalysisFromExplorer",
"when": "resourceFilename == go.mod"
},
{
"command": "fabric8.stackAnalysisFromExplorer",
"command": "rhda.stackAnalysisFromExplorer",
"when": "resourceFilename == requirements.txt"
}
],
"editor/context": [
{
"command": "fabric8.stackAnalysisFromEditor",
"command": "rhda.stackAnalysisFromEditor",
"when": "resourceFilename == package.json"
},
{
"command": "fabric8.stackAnalysisFromEditor",
"command": "rhda.stackAnalysisFromEditor",
"when": "resourceFilename == pom.xml"
},
{
"command": "fabric8.stackAnalysisFromEditor",
"command": "rhda.stackAnalysisFromEditor",
"when": "resourceFilename == go.mod"
},
{
"command": "fabric8.stackAnalysisFromEditor",
"command": "rhda.stackAnalysisFromEditor",
"when": "resourceFilename == requirements.txt"
}
],
"commandPalette": [
{
"command": "fabric8.stackAnalysisFromPieBtn",
"command": "rhda.stackAnalysisFromPieBtn",
"when": "false"
},
{
"command": "fabric8.stackAnalysisFromEditor",
"command": "rhda.stackAnalysisFromEditor",
"when": "false"
},
{
"command": "fabric8.stackAnalysisFromExplorer",
"command": "rhda.stackAnalysisFromExplorer",
"when": "false"
}
]
Expand All @@ -168,10 +173,13 @@
"default": "off",
"description": "Traces the communication between VSCode and the Red Hat Dependency Analytics Language Server."
},
"redHatDependencyAnalytics.exhortSnykToken": {
"redHatDependencyAnalytics.snykTokenStorage": {
"type": "string",
"default": "",
"description": "Red Hat Dependency Analytics authentication token for Snyk.",
"enum": [
"Always use VS Code's secret storage"
],
"default": "Always use VS Code's secret storage",
"markdownDescription": "Red Hat Dependency Analytics uses VS Code's [secret storage](https://code.visualstudio.com/api/references/vscode-api#SecretStorage) to safely store the authentication token for Snyk. To set the token, run the VS Code command [RHDA: Set Snyk Token](command:rhda.setSnykToken).",
"scope": "window"
},
"redHatDependencyAnalytics.matchManifestVersions": {
Expand Down Expand Up @@ -279,11 +287,11 @@
"webpack-cli": "^5.1.4"
},
"dependencies": {
"@fabric8-analytics/fabric8-analytics-lsp-server": "^0.9.4-ea.1",
"@fabric8-analytics/fabric8-analytics-lsp-server": "^0.9.4-ea.2",
"@redhat-developer/vscode-redhat-telemetry": "^0.7.0",
"@RHEcosystemAppEng/exhort-javascript-api": "^0.1.1-ea.14",
"fs": "^0.0.1-security",
"path": "^0.12.7",
"vscode-languageclient": "^8.1.0"
}
}
}
4 changes: 2 additions & 2 deletions src/caStatusBarProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class CAStatusBarProvider implements Disposable {
this.statusBarItem.text = text;
this.statusBarItem.command = {
title: PromptText.FULL_STACK_PROMPT_TEXT,
command: commands.TRIGGER_FULL_STACK_ANALYSIS_FROM_STATUS_BAR,
command: commands.STACK_ANALYSIS_FROM_STATUS_BAR_COMMAND,
arguments: [Uri.parse(uri)]
};
this.statusBarItem.tooltip = PromptText.FULL_STACK_PROMPT_TEXT;
Expand All @@ -41,7 +41,7 @@ class CAStatusBarProvider implements Disposable {
this.statusBarItem.text = `$(error) RHDA analysis has failed`;
this.statusBarItem.command = {
title: PromptText.LSP_FAILURE_TEXT,
command: commands.TRIGGER_STACK_LOGS,
command: commands.STACK_LOGS_COMMAND,
};
}

Expand Down
15 changes: 8 additions & 7 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
/**
* Commonly used commands to trigger Stack Analysis and supporting actions
*/
export const TRIGGER_FULL_STACK_ANALYSIS = 'fabric8.stackAnalysis';
export const TRIGGER_FULL_STACK_ANALYSIS_FROM_STATUS_BAR = 'fabric8.stackAnalysisFromStatusBar';
export const TRIGGER_FULL_STACK_ANALYSIS_FROM_EXPLORER = 'fabric8.stackAnalysisFromExplorer';
export const TRIGGER_FULL_STACK_ANALYSIS_FROM_PIE_BTN = 'fabric8.stackAnalysisFromPieBtn';
export const TRIGGER_FULL_STACK_ANALYSIS_FROM_EDITOR = 'fabric8.stackAnalysisFromEditor';
export const TRIGGER_STACK_LOGS = 'fabric8.fabric8AnalyticsStackLogs';
export const TRIGGER_REDHAT_REPOSITORY_RECOMMENDATION_NOTIFICATION = 'fabric8.RHRepositoryRecommendationNotification';
export const STACK_ANALYSIS_COMMAND = 'rhda.stackAnalysis';
export const STACK_ANALYSIS_FROM_STATUS_BAR_COMMAND = 'rhda.stackAnalysisFromStatusBar';
export const STACK_ANALYSIS_FROM_EXPLORER_COMMAND = 'rhda.stackAnalysisFromExplorer';
export const STACK_ANALYSIS_FROM_PIE_BTN_COMMAND = 'rhda.stackAnalysisFromPieBtn';
export const STACK_ANALYSIS_FROM_EDITOR_COMMAND = 'rhda.stackAnalysisFromEditor';
export const STACK_LOGS_COMMAND = 'rhda.stackLogs';
export const REDHAT_REPOSITORY_RECOMMENDATION_NOTIFICATION_COMMAND = 'rhda.rhRepositoryRecommendationNotification';
export const SET_SNYK_TOKEN_COMMAND = 'rhda.setSnykToken';
82 changes: 67 additions & 15 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import * as vscode from 'vscode';

import { GlobalState, defaultRhdaReportFilePath } from './constants';
import { GlobalState, DEFAULT_RHDA_REPORT_FILE_PATH, SNYK_TOKEN_KEY } from './constants';
import * as commands from './commands';
import { getTelemetryId } from './redhatTelemetry';

Expand All @@ -11,10 +11,9 @@ import { getTelemetryId } from './redhatTelemetry';
*/
class Config {
telemetryId: string;
triggerFullStackAnalysis: string;
triggerRHRepositoryRecommendationNotification: string;
stackAnalysisCommand: string;
rhRepositoryRecommendationNotificationCommand: string;
utmSource: string;
exhortSnykToken: string;
matchManifestVersions: string;
vulnerabilityAlertSeverity: string;
exhortMvnPath: string;
Expand All @@ -25,6 +24,7 @@ class Config {
exhortPythonPath: string;
exhortPipPath: string;
rhdaReportFilePath: string;
secrets: vscode.SecretStorage;

private readonly DEFAULT_MVN_EXECUTABLE = 'mvn';
private readonly DEFAULT_NPM_EXECUTABLE = 'npm';
Expand All @@ -40,7 +40,6 @@ class Config {
*/
constructor() {
this.loadData();
this.setProcessEnv();
}

/**
Expand All @@ -58,15 +57,14 @@ class Config {
loadData() {
const rhdaConfig = this.getRhdaConfig();

this.triggerFullStackAnalysis = commands.TRIGGER_FULL_STACK_ANALYSIS;
this.triggerRHRepositoryRecommendationNotification = commands.TRIGGER_REDHAT_REPOSITORY_RECOMMENDATION_NOTIFICATION;
this.stackAnalysisCommand = commands.STACK_ANALYSIS_COMMAND;
this.rhRepositoryRecommendationNotificationCommand = commands.REDHAT_REPOSITORY_RECOMMENDATION_NOTIFICATION_COMMAND;
this.utmSource = GlobalState.UTM_SOURCE;
this.exhortSnykToken = rhdaConfig.exhortSnykToken;
/* istanbul ignore next */
this.matchManifestVersions = rhdaConfig.matchManifestVersions ? 'true' : 'false';
this.vulnerabilityAlertSeverity = rhdaConfig.vulnerabilityAlertSeverity;
/* istanbul ignore next */
this.rhdaReportFilePath = rhdaConfig.reportFilePath || defaultRhdaReportFilePath;
this.rhdaReportFilePath = rhdaConfig.reportFilePath || DEFAULT_RHDA_REPORT_FILE_PATH;
this.exhortMvnPath = rhdaConfig.mvn.executable.path || this.DEFAULT_MVN_EXECUTABLE;
this.exhortNpmPath = rhdaConfig.npm.executable.path || this.DEFAULT_NPM_EXECUTABLE;
this.exhortGoPath = rhdaConfig.go.executable.path || this.DEFAULT_GO_EXECUTABLE;
Expand All @@ -80,11 +78,10 @@ class Config {
* Sets process environment variables based on configuration settings.
* @private
*/
private setProcessEnv() {
process.env['VSCEXT_TRIGGER_FULL_STACK_ANALYSIS'] = this.triggerFullStackAnalysis;
process.env['VSCEXT_TRIGGER_REDHAT_REPOSITORY_RECOMMENDATION_NOTIFICATION'] = this.triggerRHRepositoryRecommendationNotification;
private async setProcessEnv(): Promise<void> {
process.env['VSCEXT_STACK_ANALYSIS_COMMAND'] = this.stackAnalysisCommand;
process.env['VSCEXT_REDHAT_REPOSITORY_RECOMMENDATION_NOTIFICATION_COMMAND'] = this.rhRepositoryRecommendationNotificationCommand;
process.env['VSCEXT_UTM_SOURCE'] = this.utmSource;
process.env['VSCEXT_EXHORT_SNYK_TOKEN'] = this.exhortSnykToken;
process.env['VSCEXT_MATCH_MANIFEST_VERSIONS'] = this.matchManifestVersions;
process.env['VSCEXT_VULNERABILITY_ALERT_SEVERITY'] = this.vulnerabilityAlertSeverity;
process.env['VSCEXT_EXHORT_MVN_PATH'] = this.exhortMvnPath;
Expand All @@ -94,15 +91,70 @@ class Config {
process.env['VSCEXT_EXHORT_PIP3_PATH'] = this.exhortPip3Path;
process.env['VSCEXT_EXHORT_PYTHON_PATH'] = this.exhortPythonPath;
process.env['VSCEXT_EXHORT_PIP_PATH'] = this.exhortPipPath;
process.env['VSCEXT_TELEMETRY_ID'] = this.telemetryId;

const token = await this.getSnykToken();
process.env['VSCEXT_EXHORT_SNYK_TOKEN'] = token;
}

/**
* Authorizes the RHDA (Red Hat Dependency Analytics) service.
* @param context The extension context for authorization.
*/
async authorizeRHDA(context) {
async authorizeRHDA(context): Promise<void> {
this.telemetryId = await getTelemetryId(context);
process.env['VSCEXT_TELEMETRY_ID'] = this.telemetryId;
await this.setProcessEnv();
}

/**
* Links the secret storage to the configuration object.
* @param context The extension context.
*/
linkToSecretStorage(context) {
this.secrets = context.secrets;
}

/**
* Sets the Snyk token.
* @param token The Snyk token.
* @returns A Promise that resolves when the token is set.
*/
async setSnykToken(token: string | undefined): Promise<void> {
if (!token) { return; }

try {
await this.secrets.store(SNYK_TOKEN_KEY, token);
} catch (error) {
vscode.window.showErrorMessage(`Failed to save Snyk token to VSCode Secret Storage, Error: ${error.message}`);
}
}

/**
* Gets the Snyk token.
* @returns A Promise that resolves with the Snyk token.
*/
async getSnykToken(): Promise<string> {
try {
const token = await this.secrets.get(SNYK_TOKEN_KEY);
return token || '';
} catch (error) {
vscode.window.showErrorMessage(`Failed to get Snyk token from VSCode Secret Storage, Error: ${error.message}`);
await this.clearSnykToken();
return '';
}
}

/**
* Clears the Snyk token.
* @returns A Promise that resolves when the token is cleared.
* @private
*/
private async clearSnykToken(): Promise<void> {
try {
await this.secrets.delete(SNYK_TOKEN_KEY);
} catch (error) {
console.error(`Error while deleting Snyk token from VSCode Secret Storage, Error: ${error.message}`);
}
}
}

Expand Down
Loading

0 comments on commit 45116cc

Please sign in to comment.