Skip to content

Commit

Permalink
fix: vulnerability count message [HEAD-1024] (#391)
Browse files Browse the repository at this point in the history
  • Loading branch information
j-luong committed Nov 23, 2023
1 parent 05cc6fa commit 56bae82
Show file tree
Hide file tree
Showing 9 changed files with 258 additions and 349 deletions.
15 changes: 15 additions & 0 deletions src/snyk/common/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { JAVASCRIPT, TYPESCRIPT, HTML, PJSON } from './constants/languageConsts';

export enum Language {
TypeScript,
JavaScript,
Expand All @@ -22,3 +24,16 @@ export type ImportedModule = {
string: string;
version?: string;
};

export function languageToString(language: Language): string {
switch (language) {
case Language.TypeScript:
return TYPESCRIPT;
case Language.JavaScript:
return JAVASCRIPT;
case Language.HTML:
return HTML;
case Language.PJSON:
return PJSON;
}
}
4 changes: 2 additions & 2 deletions src/snyk/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ import { IacSuggestionWebviewProvider } from './snykIac/views/suggestion/iacSugg
import { EditorDecorator } from './snykOss/editor/editorDecorator';
import { OssService } from './snykOss/ossService';
import { OssDetailPanelProvider } from './snykOss/providers/ossDetailPanelProvider';
import { OssVulnerabilityCountProvider } from './snykOss/providers/ossVulnerabilityCountProvider';
import OssIssueTreeProvider from './snykOss/providers/ossVulnerabilityTreeProvider';
import { ModuleVulnerabilityCountProvider } from './snykOss/providers/vulnerabilityCountProvider';
import { OssVulnerabilityCountService } from './snykOss/services/vulnerabilityCount/ossVulnerabilityCountService';

class SnykExtension extends SnykLib implements IExtension {
Expand Down Expand Up @@ -379,7 +379,7 @@ class SnykExtension extends SnykLib implements IExtension {
vsCodeWorkspace,
vsCodeWindow,
vsCodeLanguages,
new ModuleVulnerabilityCountProvider(
new OssVulnerabilityCountProvider(
this.ossService,
languageClientAdapter,
new UriAdapter(),
Expand Down
16 changes: 0 additions & 16 deletions src/snyk/snykOss/constants/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,4 @@ export const messages = {
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 `;
},
},
};
11 changes: 5 additions & 6 deletions src/snyk/snykOss/editor/editorDecorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { IVSCodeLanguages } from '../../common/vscode/languages';
import { IThemeColorAdapter } from '../../common/vscode/theme';
import { TextEditorDecorationType } from '../../common/vscode/types';
import { IVSCodeWindow } from '../../common/vscode/window';
import { messages } from '../constants/messages';
import { ImportedModule, ModuleVulnerabilityCount } from '../services/vulnerabilityCount/importedModule';

export class EditorDecorator {
Expand Down Expand Up @@ -58,7 +57,7 @@ export class EditorDecorator {
module.line - 1,
this.editorLastCharacterIndex,
),
renderOptions: getRenderOptions(messages.vulnerabilityCount.fetchingVulnerabilities, this.themeColorAdapter),
renderOptions: getRenderOptions('Fetching vulnerabilities...', this.themeColorAdapter),
};
}

Expand Down Expand Up @@ -92,16 +91,16 @@ export class EditorDecorator {
this.fileDecorationMap.set(filePath, lineDecorations); // set map, if no decoration was set before
}

const text = vulnerabilityCount.count ? messages.vulnerabilityCount.decoratorMessage(vulnerabilityCount.count) : '';
const vulnerabilityCountMessage = vulnerabilityCount.count ?? 'Vulnerabilities: 0';

lineDecorations[vulnerabilityCount.line] = {
range: this.languages.createRange(
vulnerabilityCount.line - 1,
vulnerabilityCount.line - 1, // start line, index is 0 based
this.editorLastCharacterIndex,
vulnerabilityCount.line - 1,
vulnerabilityCount.line - 1, // end line, index is 0 based
this.editorLastCharacterIndex,
),
renderOptions: getRenderOptions(text, this.themeColorAdapter),
renderOptions: getRenderOptions(vulnerabilityCountMessage, this.themeColorAdapter),
};

if (triggerUpdate) {
Expand Down
132 changes: 132 additions & 0 deletions src/snyk/snykOss/providers/ossVulnerabilityCountProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { CliError } from '../../cli/services/cliService';
import { Language, languageToString } from '../../common/types';
import { ILanguageClientAdapter } from '../../common/vscode/languageClient';
import { ITextDocumentAdapter } from '../../common/vscode/textdocument';
import { InlineValueText, LanguageClient, LSPTextDocument } from '../../common/vscode/types';
import { IUriAdapter } from '../../common/vscode/uri';
import { convertIssue, isResultCliError, OssFileResult, OssResultBody } from '../interfaces';
import { OssService } from '../ossService';
import { ImportedModule, ModuleVulnerabilityCount } from '../services/vulnerabilityCount/importedModule';
import { VulnerabilityCountEmitter } from '../services/vulnerabilityCount/vulnerabilityCountEmitter';

export class OssVulnerabilityCountProvider {
constructor(
private readonly ossService: OssService,
private readonly languageClientAdapter: ILanguageClientAdapter,
private readonly uriAdapter: IUriAdapter,
private readonly textDocumentAdapter: ITextDocumentAdapter,
) {}

async getVulnerabilityCount(
fileName: string,
module: ImportedModule,
language: Language,
emitter: VulnerabilityCountEmitter,
): Promise<ModuleVulnerabilityCount> {
let moduleVulnerabilityCount: ModuleVulnerabilityCount = {
name: module.name,
fileName: module.fileName,
line: module.line,
range: module.loc,
hasCount: false,
};

const processFile = [Language.TypeScript, Language.JavaScript, Language.PJSON, Language.HTML].includes(language);
if (processFile) {
const uri = this.uriAdapter.file(fileName).toString();
const doc: LSPTextDocument = this.textDocumentAdapter.create(uri, languageToString(language), 1, '');

let firstLine = 0;
let lastLine = doc.lineCount;
let firstCharacter = 0;
let lastCharacter = Number.MAX_SAFE_INTEGER;

if (module.loc) {
firstLine = module.loc.start.line - 1;
lastLine = module.loc.end.line - 1;
firstCharacter = module.loc.start.column;
lastCharacter = module.loc.end.column;
}

const param = {
textDocument: { uri: doc.uri },
range: {
start: { line: firstLine, character: firstCharacter },
end: { line: lastLine, character: lastCharacter },
},
};

const inlineValues: InlineValueText[] = await this.languageClientAdapter
.getLanguageClient()
.sendRequest('textDocument/inlineValue', param);

if (inlineValues?.length > 0) {
moduleVulnerabilityCount = {
name: module.name,
version: module.version,
fileName: module.fileName,
line: module.line,
range: module.loc,
count: inlineValues[0].text,
hasCount: true,
};
}
}

emitter?.scanned(moduleVulnerabilityCount);
return moduleVulnerabilityCount;
}

isFilePartOfOssTest(filePath: string, ossFileResult: OssFileResult): boolean {
if (isResultCliError(ossFileResult)) {
return false;
}

// File is considered to be part of OSS test if it has common root directory between OSS result path and filename path.
// This is since package.json always lies in the root directory folder of a project.
return filePath.startsWith(ossFileResult.path);
}

public getResultArray = (): ReadonlyArray<OssFileResult> | undefined => {
if (!this.ossService.result) {
return undefined;
}

const tempResultArray: OssFileResult[] = [];
const resultCache = new Map<string, OssResultBody>();

for (const [, value] of this.ossService.result) {
// value is Error
if (value instanceof Error) {
tempResultArray.push(new CliError(value));
}
// value is Issue<T>[]
else {
for (const issue of value) {
// try to access list of vulns for the current file
let res = resultCache.get(issue.filePath);

// add list of vulns to local cache if not there yet
if (res === undefined) {
res = {
path: issue.filePath,
vulnerabilities: [],
projectName: issue.additionalData.projectName,
displayTargetFile: issue.additionalData.displayTargetFile,
packageManager: issue.additionalData.packageManager,
};
resultCache.set(issue.filePath, res);
}

const tempVuln = convertIssue(issue);
res.vulnerabilities.push(tempVuln);
}
}
}

// copy cached results to final result array
resultCache.forEach(value => tempResultArray.push(value));

return tempResultArray;
};
}
Loading

0 comments on commit 56bae82

Please sign in to comment.