diff --git a/CHANGELOG.md b/CHANGELOG.md index e2922fdba..ca79931c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # Snyk Security Changelog +## [2.7,1] +- Add the Issue View Options panel to the Snyk Security Settings. + ## [2.6.1] - Improve the validation of the custom endpoint and change the default to https://api.snyk.io. diff --git a/package.json b/package.json index 0edee8ee7..19b9409d3 100644 --- a/package.json +++ b/package.json @@ -160,6 +160,28 @@ "description": "Find and fix your IaC misconfigurations.", "default": true }, + "snyk.issueViewOptions": { + "type": "object", + "default": { + "openIssues": true, + "ignoredIssues": true + }, + "properties": { + "openIssues": { + "type": "boolean", + "description": "Open Issues", + "default": true + }, + "ignoredIssues": { + "type": "boolean", + "description": "Ignored Issues", + "default": true + } + }, + "additionalProperties": false, + "markdownDescription": "Ignores settings is currently an experimental feature. Please reach out to [support.snyk.io](https://support.snyk.io) for more details.\n\nShow the following issues:", + "scope": "window" + }, "snyk.severity": { "type": "object", "default": { diff --git a/src/snyk/common/configuration/configuration.ts b/src/snyk/common/configuration/configuration.ts index cbf876683..c54c0e6f4 100644 --- a/src/snyk/common/configuration/configuration.ts +++ b/src/snyk/common/configuration/configuration.ts @@ -19,6 +19,7 @@ import { IAC_ENABLED_SETTING, OSS_ENABLED_SETTING, SCANNING_MODE, + ISSUE_VIEW_OPTIONS_SETTING, SEVERITY_FILTER_SETTING, TRUSTED_FOLDERS, YES_BACKGROUND_OSS_NOTIFICATION_SETTING, @@ -35,6 +36,11 @@ export type FeaturesConfiguration = { iacEnabled: boolean | undefined; }; +export interface IssueViewOptions { + ignoredIssues: boolean; + openIssues: boolean; +} + export interface SeverityFilter { critical: boolean; high: boolean; @@ -101,6 +107,8 @@ export interface IConfiguration { isFedramp: boolean; + issueViewOptions: IssueViewOptions; + severityFilter: SeverityFilter; scanningMode: string | undefined; @@ -399,6 +407,20 @@ export class Configuration implements IConfiguration { ); } + get issueViewOptions(): IssueViewOptions { + const config = this.workspace.getConfiguration( + CONFIGURATION_IDENTIFIER, + this.getConfigName(ISSUE_VIEW_OPTIONS_SETTING), + ); + + return ( + config ?? { + openIssues: true, + ignoredIssues: true, + } + ); + } + get severityFilter(): SeverityFilter { const config = this.workspace.getConfiguration( CONFIGURATION_IDENTIFIER, diff --git a/src/snyk/common/constants/settings.ts b/src/snyk/common/constants/settings.ts index ab1440629..15d6babec 100644 --- a/src/snyk/common/constants/settings.ts +++ b/src/snyk/common/constants/settings.ts @@ -21,6 +21,7 @@ export const ADVANCED_AUTOMATIC_DEPENDENCY_MANAGEMENT = `${CONFIGURATION_IDENTIF export const ADVANCED_CLI_PATH = `${CONFIGURATION_IDENTIFIER}.advanced.cliPath`; export const ADVANCED_CUSTOM_LS_PATH = `${CONFIGURATION_IDENTIFIER}.advanced.languageServerPath`; +export const ISSUE_VIEW_OPTIONS_SETTING = `${CONFIGURATION_IDENTIFIER}.issueViewOptions`; export const SEVERITY_FILTER_SETTING = `${CONFIGURATION_IDENTIFIER}.severity`; export const TRUSTED_FOLDERS = `${CONFIGURATION_IDENTIFIER}.trustedFolders`; export const SCANNING_MODE = `${CONFIGURATION_IDENTIFIER}.scanningMode`; diff --git a/src/snyk/common/views/issueTreeProvider.ts b/src/snyk/common/views/issueTreeProvider.ts index d81bc3b10..77e07b2ac 100644 --- a/src/snyk/common/views/issueTreeProvider.ts +++ b/src/snyk/common/views/issueTreeProvider.ts @@ -1,6 +1,6 @@ import _, { flatten } from 'lodash'; import * as vscode from 'vscode'; // todo: invert dependency -import { IConfiguration } from '../../common/configuration/configuration'; +import { IConfiguration, IssueViewOptions } from '../../common/configuration/configuration'; import { Issue, IssueSeverity } from '../../common/languageServer/types'; import { messages as commonMessages } from '../../common/messages/analysisMessages'; import { IContextService } from '../../common/services/contextService'; @@ -119,6 +119,28 @@ export abstract class ProductIssueTreeProvider extends AnalysisTreeNodeProvid return false; // optionally overridden by products } + filterVisibleIssues(issues: Issue[]): Issue[] { + return issues.filter(issue => this.isVisibleIssue(issue, this.configuration.issueViewOptions)); + } + + protected isVisibleIssue(issue: Issue, issueViewOptions: IssueViewOptions) { + const { ignoredIssues: includeIgnoredIssues, openIssues: includeOpenIssues } = issueViewOptions; + + // Show all issues + if (includeIgnoredIssues && includeOpenIssues) { + return true; + } + + // Show issues based on options + if (includeIgnoredIssues) { + return issue.isIgnored; + } + if (includeOpenIssues) { + return !issue.isIgnored; + } + return false; + } + getResultNodes(): TreeNode[] { const nodes: TreeNode[] = []; @@ -151,8 +173,9 @@ export abstract class ProductIssueTreeProvider extends AnalysisTreeNodeProvid const fileSeverityCounts = this.initSeverityCounts(); const filteredIssues = this.filterIssues(fileIssues); + const visibleIssues = this.filterVisibleIssues(filteredIssues); - const issueNodes = filteredIssues.map(issue => { + const issueNodes = visibleIssues.map(issue => { fileSeverityCounts[issue.severity] += 1; folderVulnCount++; diff --git a/src/snyk/common/watchers/configurationWatcher.ts b/src/snyk/common/watchers/configurationWatcher.ts index 022fcea26..aa811d763 100644 --- a/src/snyk/common/watchers/configurationWatcher.ts +++ b/src/snyk/common/watchers/configurationWatcher.ts @@ -12,6 +12,7 @@ import { CODE_SECURITY_ENABLED_SETTING, IAC_ENABLED_SETTING, ADVANCED_ORGANIZATION, + ISSUE_VIEW_OPTIONS_SETTING, OSS_ENABLED_SETTING, SEVERITY_FILTER_SETTING, TRUSTED_FOLDERS, @@ -42,6 +43,8 @@ class ConfigurationWatcher implements IWatcher { return extension.viewManagerService.refreshAllCodeAnalysisViews(); } else if (key === IAC_ENABLED_SETTING) { return extension.viewManagerService.refreshIacView(); + } else if (key === ISSUE_VIEW_OPTIONS_SETTING) { + extension.viewManagerService.refreshAllViews(); } else if (key === SEVERITY_FILTER_SETTING) { return extension.viewManagerService.refreshAllViews(); } else if (key === ADVANCED_CUSTOM_ENDPOINT) { @@ -81,6 +84,7 @@ class ConfigurationWatcher implements IWatcher { ADVANCED_CUSTOM_ENDPOINT, ADVANCED_CUSTOM_LS_PATH, TRUSTED_FOLDERS, + ISSUE_VIEW_OPTIONS_SETTING, ].find(config => event.affectsConfiguration(config)); if (change) { diff --git a/src/snyk/snykOss/providers/ossVulnerabilityTreeProvider.ts b/src/snyk/snykOss/providers/ossVulnerabilityTreeProvider.ts index 1aadf6c2d..be6ba0f40 100644 --- a/src/snyk/snykOss/providers/ossVulnerabilityTreeProvider.ts +++ b/src/snyk/snykOss/providers/ossVulnerabilityTreeProvider.ts @@ -75,19 +75,21 @@ export default class OssIssueTreeProvider extends ProductIssueTreeProvider) => { - fileSeverityCounts[issue.severity] += 1; - folderVulnCount++; - - return new TreeNode({ - text: `${issue.additionalData.packageName}@${issue.additionalData.version} - ${issue.title}`, - icon: ProductIssueTreeProvider.getSeverityIcon(issue.severity), - internal: { - severity: ProductIssueTreeProvider.getSeverityComparatorIndex(issue.severity), - }, - command: this.getOpenIssueCommand(issue, folderPath, '', filteredIssues), - }); - }); + const vulnerabilityNodes: TreeNode[] = this.filterVisibleIssues(filteredIssues).map( + (issue: Issue) => { + fileSeverityCounts[issue.severity] += 1; + folderVulnCount++; + + return new TreeNode({ + text: `${issue.additionalData.packageName}@${issue.additionalData.version} - ${issue.title}`, + icon: ProductIssueTreeProvider.getSeverityIcon(issue.severity), + internal: { + severity: ProductIssueTreeProvider.getSeverityComparatorIndex(issue.severity), + }, + command: this.getOpenIssueCommand(issue, folderPath, '', filteredIssues), + }); + }, + ); if (vulnerabilityNodes.length === 0) { continue;