diff --git a/package.json b/package.json index 0f090c1b9..b7d85464a 100644 --- a/package.json +++ b/package.json @@ -217,6 +217,11 @@ "default": [], "description": "Folders to trust for Snyk scans." }, + "snyk.folderConfigs": { + "type": "array", + "default": [], + "description": "Folder configuration for Snyk scans." + }, "snyk.features.preview": { "type": "object", "default": {}, diff --git a/src/snyk/common/configuration/configuration.ts b/src/snyk/common/configuration/configuration.ts index 170ce2cfb..7a31d5899 100644 --- a/src/snyk/common/configuration/configuration.ts +++ b/src/snyk/common/configuration/configuration.ts @@ -25,6 +25,7 @@ import { YES_CRASH_REPORT_SETTING, YES_WELCOME_NOTIFICATION_SETTING, DELTA_FINDINGS, + FOLDER_CONFIGS, } from '../constants/settings'; import SecretStorageAdapter from '../vscode/secretStorage'; import { IVSCodeWorkspace } from '../vscode/workspace'; @@ -36,6 +37,13 @@ export type FeaturesConfiguration = { iacEnabled: boolean | undefined; }; + +export type FolderConfig = { + folderPath: string; + baseBranch: string; + localBranches: string[] | undefined; +}; + export interface IssueViewOptions { ignoredIssues: boolean; openIssues: boolean; @@ -122,6 +130,10 @@ export interface IConfiguration { setEndpoint(endpoint: string): Promise; getDeltaFindingsEnabled(): boolean; + + getFolderConfigs(): FolderConfig[]; + + setFolderConfigs(folderConfig: FolderConfig[]): Promise; } export class Configuration implements IConfiguration { @@ -463,6 +475,12 @@ export class Configuration implements IConfiguration { ); } + getFolderConfigs(): FolderConfig[] { + return ( + this.workspace.getConfiguration(CONFIGURATION_IDENTIFIER, this.getConfigName(FOLDER_CONFIGS)) || [] + ); + } + get scanningMode(): string | undefined { return this.workspace.getConfiguration(CONFIGURATION_IDENTIFIER, this.getConfigName(SCANNING_MODE)); } @@ -476,5 +494,14 @@ export class Configuration implements IConfiguration { ); } + async setFolderConfigs(folderConfigs: FolderConfig[]): Promise { + await this.workspace.updateConfiguration( + CONFIGURATION_IDENTIFIER, + this.getConfigName(FOLDER_CONFIGS), + folderConfigs, + true, + ); + } + private getConfigName = (setting: string) => setting.replace(`${CONFIGURATION_IDENTIFIER}.`, ''); } diff --git a/src/snyk/common/configuration/folderConfig.ts b/src/snyk/common/configuration/folderConfig.ts new file mode 100644 index 000000000..2a2c19bc2 --- /dev/null +++ b/src/snyk/common/configuration/folderConfig.ts @@ -0,0 +1,40 @@ +import { FolderConfig, IConfiguration } from './configuration'; + +export interface IFolderConfigs { + getFolderConfigs(config: IConfiguration): ReadonlyArray; + + resetFolderConfigsCache(): void; +} + +export class FolderConfigs implements IFolderConfigs { + private folderConfigsCache?: ReadonlyArray; + + getFolderConfigs(config: IConfiguration): ReadonlyArray { + if (this.folderConfigsCache !== undefined) { + return this.folderConfigsCache; + } + + const folderConfigs = config.getFolderConfigs(); + + this.folderConfigsCache = folderConfigs; + + return folderConfigs; + } + + setFolderConfig(_config: IConfiguration, _folderPath: string, _baseBranch: string) { + // Get all folders and update one you need and use setFolderConfig. + // if (this.folderConfigsCache !== undefined) { + // return this.folderConfigsCache; + // } + + // const folderConfigs = config.getFolderConfigs(); + + // this.folderConfigsCache = folderConfigs; + + // return folderConfigs; + } + + resetFolderConfigsCache() { + this.folderConfigsCache = undefined; + } +} diff --git a/src/snyk/common/constants/languageServer.ts b/src/snyk/common/constants/languageServer.ts index c6220ebdc..0f4389ffe 100644 --- a/src/snyk/common/constants/languageServer.ts +++ b/src/snyk/common/constants/languageServer.ts @@ -12,3 +12,4 @@ export const SNYK_HAS_AUTHENTICATED = '$/snyk.hasAuthenticated'; export const SNYK_CLI_PATH = '$/snyk.isAvailableCli'; export const SNYK_ADD_TRUSTED_FOLDERS = '$/snyk.addTrustedFolders'; export const SNYK_SCAN = '$/snyk.scan'; +export const SNYK_FOLDERCONFIG = '$/snyk.folderConfigs'; diff --git a/src/snyk/common/constants/settings.ts b/src/snyk/common/constants/settings.ts index 5f2cc0cfc..5a9c6b8e1 100644 --- a/src/snyk/common/constants/settings.ts +++ b/src/snyk/common/constants/settings.ts @@ -24,6 +24,7 @@ export const ADVANCED_CUSTOM_LS_PATH = `${CONFIGURATION_IDENTIFIER}.advanced.lan 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 FOLDER_CONFIGS = `${CONFIGURATION_IDENTIFIER}.folderConfigs`; export const SCANNING_MODE = `${CONFIGURATION_IDENTIFIER}.scanningMode`; export const DELTA_FINDINGS = `${FEATURES_PREVIEW_SETTING}.deltaFindings`; diff --git a/src/snyk/common/languageServer/languageServer.ts b/src/snyk/common/languageServer/languageServer.ts index 10be6c636..a581610a9 100644 --- a/src/snyk/common/languageServer/languageServer.ts +++ b/src/snyk/common/languageServer/languageServer.ts @@ -1,10 +1,11 @@ import _ from 'lodash'; import { firstValueFrom, ReplaySubject, Subject } from 'rxjs'; import { IAuthenticationService } from '../../base/services/authenticationService'; -import { IConfiguration } from '../configuration/configuration'; +import { FolderConfig, IConfiguration } from '../configuration/configuration'; import { SNYK_ADD_TRUSTED_FOLDERS, SNYK_CLI_PATH, + SNYK_FOLDERCONFIG, SNYK_HAS_AUTHENTICATED, SNYK_LANGUAGE_SERVER_NAME, SNYK_SCAN, @@ -118,7 +119,7 @@ export class LanguageServer implements ILanguageServer { }; // Create the language client and start the client. - this.client = this.languageClientAdapter.create('Snyk LS', SNYK_LANGUAGE_SERVER_NAME, serverOptions, clientOptions); + this.client = this.languageClientAdapter.create('SnykLS', SNYK_LANGUAGE_SERVER_NAME, serverOptions, clientOptions); try { // Start the client. This will also launch the server @@ -138,6 +139,12 @@ export class LanguageServer implements ILanguageServer { }); }); + client.onNotification(SNYK_FOLDERCONFIG, ({ folderConfigs }: { folderConfigs: FolderConfig[] }) => { + this.configuration.setFolderConfigs(folderConfigs).catch((error: Error) => { + ErrorHandler.handle(error, this.logger, error.message); + }); + }); + client.onNotification(SNYK_CLI_PATH, ({ cliPath }: { cliPath: string }) => { if (!cliPath) { ErrorHandler.handle( diff --git a/src/snyk/common/languageServer/settings.ts b/src/snyk/common/languageServer/settings.ts index b240b6584..4276429c9 100644 --- a/src/snyk/common/languageServer/settings.ts +++ b/src/snyk/common/languageServer/settings.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; import { CLI_INTEGRATION_NAME } from '../../cli/contants/integration'; -import { Configuration, IConfiguration, SeverityFilter } from '../configuration/configuration'; +import { Configuration, FolderConfig, IConfiguration, SeverityFilter } from '../configuration/configuration'; import { User } from '../user'; import { PROTOCOL_VERSION } from '../constants/languageServer'; @@ -41,6 +41,7 @@ export type ServerSettings = { deviceId?: string; requiredProtocolVersion?: string; enableDeltaFindings?: string; + folderConfigs: FolderConfig[]; }; export class LanguageServerSettings { @@ -80,6 +81,7 @@ export class LanguageServerSettings { integrationVersion: await Configuration.getVersion(), deviceId: user.anonymousId, requiredProtocolVersion: `${PROTOCOL_VERSION}`, + folderConfigs: configuration.getFolderConfigs() }; } } diff --git a/src/test/unit/common/languageServer/languageServer.test.ts b/src/test/unit/common/languageServer/languageServer.test.ts index 8f406a57e..24a01eeac 100644 --- a/src/test/unit/common/languageServer/languageServer.test.ts +++ b/src/test/unit/common/languageServer/languageServer.test.ts @@ -223,6 +223,7 @@ suite('Language Server', () => { insecure: 'true', requiredProtocolVersion: '12', scanningMode: 'auto', + folderConfigs: [] }; deepStrictEqual(await languageServer.getInitializationOptions(), expectedInitializationOptions);