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: html vscode script for buttons and links [IDE-375] [IDE-367] #465

Merged
merged 3 commits into from
Jun 4, 2024
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
9 changes: 6 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# Snyk Security Changelog

## [2.9.2]
- Injects custom styling for the HTML panel used by Snyk Code for consistent ignores.
## [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.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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
border: 1px solid #E27122;
}

.data-flow-clickable-row {
color: var(--vscode-textLink-foreground);
}

.tabs-nav {}

.tab-item {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}', '<style nonce=${nonce}>' + ideStyle + '</style>');
html = html.replace('${ideScript}', '<script nonce=${nonce}>' + ideScript + '</script>');
const nonce = getNonce();
html = html.replaceAll('${nonce}', nonce);

Expand Down
161 changes: 161 additions & 0 deletions src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScriptLS.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/* 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 */
/// <reference lib="dom" />

// 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, position: MarkerPosition) {
if (!suggestion) return;
const message: OpenLocalMessage = {
type: 'openLocal',
args: {
...getSuggestionPosition(suggestion, position),
suggestionUri: suggestion.filePath,
},
};

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?: MarkerPosition) {
return {
uri: position?.file ?? suggestionParam.filePath,
rows: position ? position.rows : suggestionParam.rows,
cols: position ? position.cols : suggestionParam.cols,
};
}

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;
}
}
});
})();
Loading