From 607a35ccd9d14ca99119c3f018f1e56b6283943e Mon Sep 17 00:00:00 2001 From: Teodora Sandu Date: Tue, 4 Jun 2024 09:35:36 +0100 Subject: [PATCH 1/3] feat: vscode script for html --- CHANGELOG.md | 5 +- .../{suggestion_ls.scss => suggestionLS.scss} | 4 + .../codeSuggestionWebviewProvider.ts | 13 +- .../codeSuggestionWebviewScriptLS.ts | 159 ++++++++++++++++++ 4 files changed, 179 insertions(+), 2 deletions(-) rename media/views/snykCode/suggestion/{suggestion_ls.scss => suggestionLS.scss} (96%) create mode 100644 src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScriptLS.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index cb3fc02c0..ec3e3ee1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ # Snyk Security Changelog +## [2.10.0] +- Add warning messages in the Tree View for the issue view options used in consistent ignores. +- Add Data Flow and Ignore Footer intractions for Consistent Ignores flows. + ## [2.9.2] - Injects custom styling for the HTML panel used by Snyk Code for consistent ignores. -- Add warning messages in the Tree View for the issue view options used in consistent ignores. ## [2.8.1] - Lower the strictness of custom endpoint regex validation so that single tenant APIs are allowed. diff --git a/media/views/snykCode/suggestion/suggestion_ls.scss b/media/views/snykCode/suggestion/suggestionLS.scss similarity index 96% rename from media/views/snykCode/suggestion/suggestion_ls.scss rename to media/views/snykCode/suggestion/suggestionLS.scss index 4566a31bc..6e155e491 100644 --- a/media/views/snykCode/suggestion/suggestion_ls.scss +++ b/media/views/snykCode/suggestion/suggestionLS.scss @@ -10,6 +10,10 @@ border: 1px solid #E27122; } +.data-flow-clickable-row { + color: var(--vscode-textLink-foreground); +} + .tabs-nav {} .tab-item { diff --git a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts index 425a29a18..82e57bd0a 100644 --- a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts +++ b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts @@ -125,10 +125,21 @@ export class CodeSuggestionWebviewProvider 'views', 'snykCode', 'suggestion', - 'suggestion_ls.css', + 'suggestionLS.css', ); const ideStyle = readFileSync(ideStylePath.path, 'utf8'); + const ideScriptPath = vscode.Uri.joinPath( + vscode.Uri.file(this.context.extensionPath), + 'out', + 'snyk', + 'snykCode', + 'views', + 'suggestion', + 'codeSuggestionWebviewScriptLS.js', + ); + const ideScript = readFileSync(ideScriptPath.path, 'utf8'); html = html.replace('${ideStyle}', ''); + html = html.replace('${ideScript}', ''); const nonce = getNonce(); html = html.replaceAll('${nonce}', nonce); diff --git a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScriptLS.ts b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScriptLS.ts new file mode 100644 index 000000000..7381663b4 --- /dev/null +++ b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScriptLS.ts @@ -0,0 +1,159 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ + +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/// + +// This script will be run within the webview itself +// It cannot access the main VS Code APIs directly. +(function () { + // TODO: Redefine types until bundling is introduced into extension + // https://stackoverflow.com/a/56938089/1713082 + type Marker = { + msg: Point; + pos: MarkerPosition[]; + }; + type MarkerPosition = { + cols: Point; + rows: Point; + file: string; + }; + type Point = [number, number]; + type Suggestion = { + id: string; + message: string; + severity: 'Low' | 'Medium' | 'High'; + rule: string; + cwe: string[]; + title: string; + text: string; + markers?: Marker[]; + cols: Point; + rows: Point; + hasAIFix: boolean; + filePath: string; + }; + + type OpenLocalMessage = { + type: 'openLocal'; + args: { + uri: string; + cols: [number, number]; + rows: [number, number]; + suggestionUri: string; + }; + }; + + type IgnoreIssueMessage = { + type: 'ignoreIssue'; + args: { + id: string; + severity: 'Low' | 'Medium' | 'High'; + lineOnly: boolean; + message: string; + rule: string; + uri: string; + cols: [number, number]; + rows: [number, number]; + }; + }; + + type SetSuggestionMessage = { + type: 'set'; + args: Suggestion; + }; + + type GetSuggestionMessage = { + type: 'get'; + }; + + type SuggestionMessage = + | OpenLocalMessage + | IgnoreIssueMessage + | SetSuggestionMessage + | GetSuggestionMessage + + const vscode = acquireVsCodeApi(); + + function sendMessage(message: SuggestionMessage) { + vscode.postMessage(message); + } + + function navigateToIssue(_e: any, range: any) { + if (!suggestion) return; + const message: OpenLocalMessage = { + type: 'openLocal', + args: getSuggestionPosition(suggestion, range), + }; + + sendMessage(message); + } + + let suggestion: Suggestion | null = vscode.getState()?.suggestion || null; + + function ignoreIssue(lineOnly: boolean) { + if (!suggestion) return; + + const message: IgnoreIssueMessage = { + type: 'ignoreIssue', + args: { + ...getSuggestionPosition(suggestion), + message: suggestion.message, + rule: suggestion.rule, + id: suggestion.id, + severity: suggestion.severity, + lineOnly: lineOnly, + }, + }; + sendMessage(message); + } + + function getSuggestionPosition(suggestionParam: Suggestion, position?: { file: string; rows: any; cols: any }) { + return { + uri: position?.file ?? suggestionParam.filePath, + rows: position ? position.rows : suggestionParam.rows, + cols: position ? position.cols : suggestionParam.cols, + suggestionUri: suggestionParam.filePath, + }; + } + + const dataFlows = document.getElementsByClassName('data-flow-clickable-row') + for(let i = 0; i < dataFlows.length; i++) { + dataFlows[i].addEventListener('click', (e) => { + if (!suggestion) { + return; + } + const markers = suggestion.markers + if (!markers) { + return; + } + navigateToIssue(e, { file: suggestion?.filePath, rows: markers[i]?.pos[0].rows, cols: markers[i].pos[0].cols } ) + }); + } + document.getElementById('ignore-line-issue')!.addEventListener('click', () => { + ignoreIssue(true); + }); + document.getElementById('ignore-file-issue')!.addEventListener('click', () => { + ignoreIssue(false); + }); + + window.addEventListener('message', event => { + const message = event.data as SuggestionMessage; + switch (message.type) { + case 'set': { + suggestion = message.args; + vscode.setState({ ...vscode.getState(), suggestion }); + break; + } + case 'get': { + const newSuggestion = vscode.getState()?.suggestion || {}; + if (newSuggestion != suggestion) { + suggestion = newSuggestion; + } + break; + } + } + }); +})(); From 6c18e7e98cb32e2702d58aa14695b987858e084a Mon Sep 17 00:00:00 2001 From: Teodora Sandu Date: Tue, 4 Jun 2024 10:23:30 +0100 Subject: [PATCH 2/3] chore: fix the CHANGELOG --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec3e3ee1a..82ddf31b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,13 @@ # Snyk Security Changelog -## [2.10.0] +## [2.11.0] - Add warning messages in the Tree View for the issue view options used in consistent ignores. - Add Data Flow and Ignore Footer intractions for Consistent Ignores flows. -## [2.9.2] +## [2.10.0] - Injects custom styling for the HTML panel used by Snyk Code for consistent ignores. -## [2.8.1] +## [2.9.0] - Lower the strictness of custom endpoint regex validation so that single tenant APIs are allowed. ## [2.8.0] From 213847701f22f447b73d5766921049f0a9185c47 Mon Sep 17 00:00:00 2001 From: Teodora Sandu Date: Tue, 4 Jun 2024 10:43:34 +0100 Subject: [PATCH 3/3] chore: linting --- .../codeSuggestionWebviewScriptLS.ts | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScriptLS.ts b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScriptLS.ts index 7381663b4..b968b3585 100644 --- a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScriptLS.ts +++ b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScriptLS.ts @@ -69,11 +69,7 @@ type: 'get'; }; - type SuggestionMessage = - | OpenLocalMessage - | IgnoreIssueMessage - | SetSuggestionMessage - | GetSuggestionMessage + type SuggestionMessage = OpenLocalMessage | IgnoreIssueMessage | SetSuggestionMessage | GetSuggestionMessage; const vscode = acquireVsCodeApi(); @@ -81,11 +77,14 @@ vscode.postMessage(message); } - function navigateToIssue(_e: any, range: any) { + function navigateToIssue(_e: any, position: MarkerPosition) { if (!suggestion) return; const message: OpenLocalMessage = { type: 'openLocal', - args: getSuggestionPosition(suggestion, range), + args: { + ...getSuggestionPosition(suggestion, position), + suggestionUri: suggestion.filePath, + }, }; sendMessage(message); @@ -110,27 +109,30 @@ sendMessage(message); } - function getSuggestionPosition(suggestionParam: Suggestion, position?: { file: string; rows: any; cols: any }) { + function getSuggestionPosition(suggestionParam: Suggestion, position?: MarkerPosition) { return { uri: position?.file ?? suggestionParam.filePath, rows: position ? position.rows : suggestionParam.rows, cols: position ? position.cols : suggestionParam.cols, - suggestionUri: suggestionParam.filePath, }; } - - const dataFlows = document.getElementsByClassName('data-flow-clickable-row') - for(let i = 0; i < dataFlows.length; i++) { - dataFlows[i].addEventListener('click', (e) => { + + const dataFlows = document.getElementsByClassName('data-flow-clickable-row'); + for (let i = 0; i < dataFlows.length; i++) { + dataFlows[i].addEventListener('click', e => { if (!suggestion) { return; } - const markers = suggestion.markers + const markers = suggestion.markers; if (!markers) { return; } - navigateToIssue(e, { file: suggestion?.filePath, rows: markers[i]?.pos[0].rows, cols: markers[i].pos[0].cols } ) - }); + navigateToIssue(e, { + file: suggestion.filePath, + rows: markers[i].pos[0].rows, + cols: markers[i].pos[0].cols, + }); + }); } document.getElementById('ignore-line-issue')!.addEventListener('click', () => { ignoreIssue(true);