Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Language Server based OSS tree view #386

Merged
merged 14 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"activationEvents": [
"onWebviewPanel:snyk.views.suggestion.code",
"onWebviewPanel:snyk.views.suggestion.oss",
"onWebviewPanel:snyk.views.suggestion.oss.languageServer",
"*"
],
"main": "./out/extension.js",
Expand Down Expand Up @@ -235,6 +236,11 @@
"name": "Snyk",
"when": "!snyk:loggedIn || snyk:error || !snyk:workspaceFound"
},
{
"id": "snyk.views.analysis.oss.languageServer",
"name": "Open Source Security (LS)",
"when": "snyk:initialized && snyk:loggedIn && snyk:workspaceFound && !snyk:error"
},
{
"id": "snyk.views.analysis.oss",
"name": "Open Source Security",
Expand Down
7 changes: 4 additions & 3 deletions src/snyk/common/commands/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { completeFileSuggestionType } from '../../snykCode/interfaces';
import { CodeIssueCommandArg } from '../../snykCode/views/interfaces';
import { IacIssueCommandArg } from '../../snykIac/views/interfaces';
import { OssIssueCommandArgLanguageServer } from '../../snykOss/interfaces';
import { OssIssueCommandArg } from '../../snykOss/views/ossVulnerabilityTreeProvider';
import { CodeIssueData, Issue } from '../languageServer/types';

Expand All @@ -11,19 +12,19 @@ export enum OpenCommandIssueType {
}

export type OpenIssueCommandArg = {
issue: CodeIssueCommandArg | OssIssueCommandArg | IacIssueCommandArg;
issue: CodeIssueCommandArg | OssIssueCommandArg | IacIssueCommandArg | OssIssueCommandArgLanguageServer;
issueType: OpenCommandIssueType;
};

export const isCodeIssue = (
_issue: completeFileSuggestionType | Issue<CodeIssueData> | OssIssueCommandArg,
_issue: completeFileSuggestionType | Issue<CodeIssueData> | OssIssueCommandArg | OssIssueCommandArgLanguageServer,
issueType: OpenCommandIssueType,
): _issue is Issue<CodeIssueData> => {
return issueType === OpenCommandIssueType.CodeIssue;
};

export const isOssIssue = (
_issue: completeFileSuggestionType | Issue<CodeIssueData> | OssIssueCommandArg,
_issue: completeFileSuggestionType | Issue<CodeIssueData> | OssIssueCommandArg | OssIssueCommandArgLanguageServer,
issueType: OpenCommandIssueType,
): _issue is OssIssueCommandArg => {
return issueType === OpenCommandIssueType.OssVulnerability;
Expand Down
2 changes: 2 additions & 0 deletions src/snyk/common/constants/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ export const SNYK_VIEW_ANALYSIS_CODE_ENABLEMENT = 'snyk.views.analysis.code.enab
export const SNYK_VIEW_ANALYSIS_CODE_SECURITY = 'snyk.views.analysis.code.security';
export const SNYK_VIEW_ANALYSIS_CODE_QUALITY = 'snyk.views.analysis.code.quality';
export const SNYK_VIEW_ANALYSIS_OSS = 'snyk.views.analysis.oss';
export const SNYK_VIEW_ANALYSIS_OSS_LANGUAGE_SERVER = 'snyk.views.analysis.oss.languageServer';
export const SNYK_VIEW_SUPPORT = 'snyk.views.support';
export const SNYK_VIEW_SUGGESTION_CODE = 'snyk.views.suggestion.code';
export const SNYK_VIEW_SUGGESTION_OSS = 'snyk.views.suggestion.oss';
export const SNYK_VIEW_SUGGESTION_OSS_LANGUAGE_SERVER = 'snyk.views.suggestion.oss.languageServer';
export const SNYK_VIEW_SUGGESTION_IAC = 'snyk.views.suggestion.iac';
export const SNYK_VIEW_ANALYSIS_IAC = 'snyk.views.analysis.configuration';

Expand Down
11 changes: 8 additions & 3 deletions src/snyk/common/views/issueTreeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,13 @@ export abstract class ProductIssueTreeProvider<T> extends AnalysisTreeNodeProvid
abstract getRunTestMessage(): string;
abstract getIssueTitle(issue: Issue<T>): string;

abstract getIssueRange(issue: Issue<T>): Range;
abstract getOpenIssueCommand(issue: Issue<T>, folderPath: string, filePath: string): Command;
abstract getIssueRange(issue?: Issue<T>): Range | undefined;
abstract getOpenIssueCommand(
issue: Issue<T>,
folderPath: string,
filePath: string,
filteredIssues?: Issue<T>[],
): Command;

getRootChildren(): TreeNode[] {
const nodes: TreeNode[] = [];
Expand Down Expand Up @@ -229,7 +234,7 @@ export abstract class ProductIssueTreeProvider<T> extends AnalysisTreeNodeProvid
return IssueSeverity.Low;
}

private initSeverityCounts(): ISeverityCounts {
protected initSeverityCounts(): ISeverityCounts {
return {
[IssueSeverity.Critical]: 0,
[IssueSeverity.High]: 0,
Expand Down
51 changes: 36 additions & 15 deletions src/snyk/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
SNYK_VIEW_ANALYSIS_CODE_SECURITY,
SNYK_VIEW_ANALYSIS_IAC,
SNYK_VIEW_ANALYSIS_OSS,
SNYK_VIEW_ANALYSIS_OSS_LANGUAGE_SERVER,
SNYK_VIEW_SUPPORT,
SNYK_VIEW_WELCOME,
} from './common/constants/views';
Expand Down Expand Up @@ -75,12 +76,13 @@ import IacIssueTreeProvider from './snykIac/views/iacIssueTreeProvider';
import { IacSuggestionWebviewProvider } from './snykIac/views/suggestion/iacSuggestionWebviewProvider';
import { EditorDecorator } from './snykOss/editor/editorDecorator';
import { OssServiceLanguageServer } from './snykOss/ossServiceLanguageServer';
import { OssDetailPanelProvider } from './snykOss/providers/ossDetailPanelProvider';
import OssIssueTreeProvider from './snykOss/providers/ossVulnerabilityTreeProvider';
import { OssService } from './snykOss/services/ossService';
import { OssVulnerabilityCountService } from './snykOss/services/vulnerabilityCount/ossVulnerabilityCountService';
import { ModuleVulnerabilityCountProvider } from './snykOss/services/vulnerabilityCount/vulnerabilityCountProvider';
import { OssVulnerabilityTreeProvider } from './snykOss/views/ossVulnerabilityTreeProvider';
import { OssSuggestionWebviewProvider } from './snykOss/views/suggestion/ossSuggestionWebviewProvider';
import { OssSuggestionWebviewProviderLanguageServer } from './snykOss/views/suggestion/ossSuggestionWebviewProviderLanguageServer';
import { DailyScanJob } from './snykOss/watchers/dailyScanJob';

class SnykExtension extends SnykLib implements IExtension {
Expand Down Expand Up @@ -225,7 +227,7 @@ class SnykExtension extends SnykLib implements IExtension {
this.workspaceTrust,
);

const ossSuggestionProvider = new OssSuggestionWebviewProviderLanguageServer(
const ossSuggestionProvider = new OssDetailPanelProvider(
vsCodeWindow,
extensionContext,
Logger,
Expand Down Expand Up @@ -288,19 +290,20 @@ class SnykExtension extends SnykLib implements IExtension {
this.registerCommands(vscodeContext);

const codeSecurityIssueProvider = new CodeSecurityIssueTreeProvider(
this.viewManagerService,
this.contextService,
this.snykCode,
configuration,
vsCodeLanguages,
),
codeQualityIssueProvider = new CodeQualityIssueTreeProvider(
this.viewManagerService,
this.contextService,
this.snykCode,
configuration,
vsCodeLanguages,
);
this.viewManagerService,
this.contextService,
this.snykCode,
configuration,
vsCodeLanguages,
);

const codeQualityIssueProvider = new CodeQualityIssueTreeProvider(
this.viewManagerService,
this.contextService,
this.snykCode,
configuration,
vsCodeLanguages,
);

const codeSecurityTree = vscode.window.createTreeView(SNYK_VIEW_ANALYSIS_CODE_SECURITY, {
treeDataProvider: codeSecurityIssueProvider,
Expand Down Expand Up @@ -345,6 +348,23 @@ class SnykExtension extends SnykLib implements IExtension {
codeEnablementTree,
);

const ossIssueProvider = new OssIssueTreeProvider(
this.viewManagerService,
this.contextService,
this.ossServiceLanguageServer,
configuration,
vsCodeLanguages,
);

const ossSecurityTree = vscode.window.createTreeView(SNYK_VIEW_ANALYSIS_OSS_LANGUAGE_SERVER, {
treeDataProvider: ossIssueProvider,
});

vscodeContext.subscriptions.push(
vscode.window.registerTreeDataProvider(SNYK_VIEW_ANALYSIS_OSS_LANGUAGE_SERVER, ossIssueProvider),
ossSecurityTree,
);

const iacIssueProvider = new IacIssueTreeProvider(
this.viewManagerService,
this.contextService,
Expand Down Expand Up @@ -380,6 +400,7 @@ class SnykExtension extends SnykLib implements IExtension {
this.ossService.activateSuggestionProvider();
this.ossService.activateManifestFileWatcher(this);
this.iacService.activateWebviewProviders();
this.ossServiceLanguageServer.activateWebviewProviders();

// noinspection ES6MissingAwait
void this.notificationService.init();
Expand Down
12 changes: 12 additions & 0 deletions src/snyk/snykOss/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as vscode from 'vscode';
import { Issue, OssIssueData } from '../common/languageServer/types';
import { IWebViewProvider } from '../common/views/webviewProvider';

export interface IOssSuggestionWebviewProvider extends IWebViewProvider<Issue<OssIssueData>> {
openIssueId: string | undefined;
}

export type OssIssueCommandArgLanguageServer = Issue<OssIssueData> & {
matchingIdVulnerabilities: Issue<OssIssueData>[];
overviewHtml: string;
};
50 changes: 50 additions & 0 deletions src/snyk/snykOss/messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ModuleVulnerabilityCount } from './services/vulnerabilityCount/importedModule';

export const messages = {
analysis: {
scanFailed: 'Scan failed',
noWorkspaceTrust: 'No workspace folder was granted trust',
clickToProblem: 'Click here to see the problem.',
scanRunning: 'Scanning...',
allSeverityFiltersDisabled: 'Please enable severity filters to see the results.',
duration: (time: string, day: string): string => `Analysis finished at ${time}, ${day}`,
noWorkspaceTrustDescription:
'None of workspace folders were trusted. If you trust the workspace, you can add it to the list of trusted folders in the extension settings, or when prompted by the extension next time.',
},
errors: {
suggestionViewShowFailed: 'Failed to show Snyk OSS suggestion view',
},
test: {
testFailed: 'Open Source Security test failed.',
testStarted: 'Open Source Security test started.',
viewResults: 'View results',
hide: "Don't show again",
testFailedForPath: (path: string): string => `Open Source Security test failed for "${path}".`,
testFinished: (projectName: string): string => `Open Source Security test finished for "${projectName}".`,
},
treeView: {
cookingDependencies: 'Scanning...',
runTest: 'Run scan for Open Source security vulnerabilities.',
noVulnerabilitiesFound: ' ✅ Congrats! Snyk found no vulnerabilities.',
singleVulnerabilityFound: 'Snyk found 1 vulnerability',
vulnerability: 'vulnerability',
vulnerabilities: 'vulnerabilities',
multipleVulnerabilitiesFound: (issueCount: number): string => `Snyk found ${issueCount} vulnerabilities`,
},
vulnerabilityCount: {
fetchingVulnerabilities: 'Fetching vulnerabilities...',
vulnerability: 'vulnerability',
vulnerabilities: 'vulnerabilities',
showMostSevereVulnerability: 'Show the most severe vulnerability (Snyk)',
decoratorMessage: (vulnerabilityCount: string): string => {
const vulnerabilityCountNumber = Number.parseInt(vulnerabilityCount, 10);
if (isNaN(vulnerabilityCountNumber)) {
return vulnerabilityCount;
}
return `${vulnerabilityCountNumber} ${vulnerabilityCountNumber > 1 ? 'vulnerabilities' : 'vulnerability'}`;
},
diagnosticMessagePrefix: (module: ModuleVulnerabilityCount): string => {
return `Dependency ${module.name}${module.version ? `@${module.version}` : ''} has `;
},
},
};
2 changes: 1 addition & 1 deletion src/snyk/snykOss/ossServiceLanguageServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { ICodeActionAdapter, ICodeActionKindAdapter } from '../common/vscode/cod
import { ExtensionContext } from '../common/vscode/extensionContext';
import { IVSCodeLanguages } from '../common/vscode/languages';
import { IVSCodeWorkspace } from '../common/vscode/workspace';
import { IOssSuggestionWebviewProvider } from './views/interfaces';
import { IOssSuggestionWebviewProvider } from './interfaces';

export class OssServiceLanguageServer extends ProductService<OssIssueData> {
constructor(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import * as vscode from 'vscode';
import { SNYK_OPEN_BROWSER_COMMAND } from '../../../common/constants/commands';
import { SNYK_VIEW_SUGGESTION_IAC, SNYK_VIEW_SUGGESTION_OSS } from '../../../common/constants/views';
import { ErrorHandler } from '../../../common/error/errorHandler';
import { IacIssueData, Issue, OssIssueData } from '../../../common/languageServer/types';
import { ILog } from '../../../common/logger/interfaces';
import { getNonce } from '../../../common/views/nonce';
import { WebviewPanelSerializer } from '../../../common/views/webviewPanelSerializer';
import { IWebViewProvider, WebviewProvider } from '../../../common/views/webviewProvider';
import { ExtensionContext } from '../../../common/vscode/extensionContext';
import { IVSCodeLanguages } from '../../../common/vscode/languages';
import { IVSCodeWindow } from '../../../common/vscode/window';
import { IVSCodeWorkspace } from '../../../common/vscode/workspace';
import { messages as errorMessages } from '../../messages/error';
// import { getAbsoluteMarkerFilePath } from '../../utils/analysisUtils';
// import { IssueUtils } from '../../utils/issueUtils';
// import { ICodeSuggestionWebviewProvider } from '../interfaces';

export class OssSuggestionWebviewProviderLanguageServer
import { SNYK_OPEN_BROWSER_COMMAND } from '../../common/constants/commands';
import { SNYK_VIEW_SUGGESTION_OSS_LANGUAGE_SERVER } from '../../common/constants/views';
import { ErrorHandler } from '../../common/error/errorHandler';
import { Issue, OssIssueData } from '../../common/languageServer/types';
import { ILog } from '../../common/logger/interfaces';
import { getNonce } from '../../common/views/nonce';
import { WebviewPanelSerializer } from '../../common/views/webviewPanelSerializer';
import { IWebViewProvider, WebviewProvider } from '../../common/views/webviewProvider';
import { ExtensionContext } from '../../common/vscode/extensionContext';
import { IVSCodeLanguages } from '../../common/vscode/languages';
import { IVSCodeWindow } from '../../common/vscode/window';
import { IVSCodeWorkspace } from '../../common/vscode/workspace';
import { messages as errorMessages } from '../messages/error';

export class OssDetailPanelProvider
extends WebviewProvider<Issue<OssIssueData>>
implements IWebViewProvider<Issue<OssIssueData>>
{
Expand All @@ -36,7 +33,10 @@ export class OssSuggestionWebviewProviderLanguageServer

activate(): void {
this.context.addDisposables(
this.window.registerWebviewPanelSerializer(SNYK_VIEW_SUGGESTION_OSS, new WebviewPanelSerializer(this)),
this.window.registerWebviewPanelSerializer(
SNYK_VIEW_SUGGESTION_OSS_LANGUAGE_SERVER,
new WebviewPanelSerializer(this),
),
);
}

Expand All @@ -52,7 +52,7 @@ export class OssSuggestionWebviewProviderLanguageServer
this.panel.reveal(vscode.ViewColumn.Two, true);
} else {
this.panel = vscode.window.createWebviewPanel(
SNYK_VIEW_SUGGESTION_OSS,
SNYK_VIEW_SUGGESTION_OSS_LANGUAGE_SERVER,
'Snyk OSS Vulnerability',
{
viewColumn: vscode.ViewColumn.Two,
Expand Down
Loading
Loading