diff --git a/.runUnit/Unit Tests.run.xml b/.runUnit/Unit Tests.run.xml
new file mode 100644
index 000000000..20d99622c
--- /dev/null
+++ b/.runUnit/Unit Tests.run.xml
@@ -0,0 +1,25 @@
+
+
+ project
+
+ $PROJECT_DIR$/node_modules/mocha
+ $PROJECT_DIR$/
+ true
+ tdd
+ -c 'out/test/unit/**/*.test.js'
+ DIRECTORY
+ $PROJECT_DIR$/src/test/unit
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 16d6bd397..7f1a95bef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,9 @@
# Snyk Security - Code and Open Source Dependencies Changelog
+## [1.18.3]
+
+### Added
+- Added support for OAuth2 authentication
+- Snyk Learn: now uses language server to retrieve lessons
## [1.19.1]
diff --git a/package.json b/package.json
index dd34f3e38..7250d806a 100644
--- a/package.json
+++ b/package.json
@@ -265,7 +265,7 @@
{
"id": "snyk.views.analysis.code.security",
"name": "Code Security",
- "when": "snyk:lsCodePreview && snyk:loggedIn && snyk:featuresSelected && snyk:codeEnabled && !snyk:codeLocalEngineEnabled && snyk:workspaceFound && !snyk:error"
+ "when": "snyk:lsCodePreview && snyk:loggedIn && snyk:codeEnabled && !snyk:codeLocalEngineEnabled && snyk:featuresSelected && snyk:workspaceFound && !snyk:error"
},
{
"id": "snyk.views.analysis.configuration",
@@ -275,17 +275,17 @@
{
"id": "snyk.views.analysis.code.quality",
"name": "Code Quality",
- "when": "snyk:lsCodePreview && snyk:loggedIn && snyk:featuresSelected && snyk:codeEnabled && !snyk:codeLocalEngineEnabled && snyk:workspaceFound && !snyk:error"
+ "when": "snyk:lsCodePreview && snyk:loggedIn && snyk:codeEnabled && !snyk:codeLocalEngineEnabled && snyk:featuresSelected && snyk:workspaceFound && !snyk:error"
},
{
"id": "snyk.views.analysis.code.enablement",
"name": "Code Security & Quality",
- "when": "snyk:loggedIn && !snyk:lsCodePreview && snyk:featuresSelected && !snyk:codeEnabled && snyk:workspaceFound && !snyk:error"
+ "when": "snyk:loggedIn && snyk:featuresSelected && !snyk:codeEnabled && snyk:workspaceFound && !snyk:error"
},
{
"id": "snyk.views.analysis.code.localEngine",
"name": "Code Security & Quality",
- "when": "snyk:loggedIn && !snyk:lsCodePreview && snyk:featuresSelected && snyk:codeEnabled && snyk:codeLocalEngineEnabled && snyk:workspaceFound && !snyk:error"
+ "when": "snyk:loggedIn && snyk:featuresSelected && snyk:codeEnabled && snyk:codeLocalEngineEnabled && snyk:workspaceFound && !snyk:error"
},
{
"id": "snyk.views.support",
@@ -402,7 +402,7 @@
},
"scripts": {
"vscode:prepublish": "tsc -p ./ && sass media --no-source-map",
- "build": "tsc -p ./",
+ "build": "npm run vscode:prepublish",
"watch": "tsc -watch -p ./",
"watch-resources": "sass media --no-source-map --watch",
"watch-all": "concurrently --kill-others 'npm run watch' 'npm run watch-resources'",
diff --git a/src/snyk/base/modules/baseSnykModule.ts b/src/snyk/base/modules/baseSnykModule.ts
index e98e3882a..a2771f697 100644
--- a/src/snyk/base/modules/baseSnykModule.ts
+++ b/src/snyk/base/modules/baseSnykModule.ts
@@ -2,7 +2,6 @@ import { AdvisorApiClient, IAdvisorApiClient } from '../../advisor/services/advi
import AdvisorProvider from '../../advisor/services/advisorProvider';
import { AdvisorService } from '../../advisor/services/advisorService';
import { IAnalytics } from '../../common/analytics/itly';
-import { ISnykApiClient, SnykApiClient } from '../../common/api/apiСlient';
import { CommandController } from '../../common/commands/commandController';
import { configuration } from '../../common/configuration/instance';
import { IWorkspaceTrust, WorkspaceTrust } from '../../common/configuration/trustedFolders';
@@ -25,7 +24,7 @@ import { IMarkdownStringAdapter, MarkdownStringAdapter } from '../../common/vsco
import { vsCodeWorkspace } from '../../common/vscode/workspace';
import { IWatcher } from '../../common/watchers/interfaces';
import { ISnykCodeServiceOld } from '../../snykCode/codeServiceOld';
-import { CodeSettings, ICodeSettings } from '../../snykCode/codeSettings';
+import { ICodeSettings } from '../../snykCode/codeSettings';
import { ISnykCodeErrorHandler, SnykCodeErrorHandler } from '../../snykCode/error/snykCodeErrorHandler';
import { FalsePositiveApi, IFalsePositiveApi } from '../../snykCode/falsePositive/api/falsePositiveApi';
import SnykEditorsWatcher from '../../snykCode/watchers/editorsWatcher';
@@ -52,7 +51,6 @@ export default abstract class BaseSnykModule implements IBaseSnykModule {
protected downloadService: DownloadService;
protected ossService?: OssService;
protected advisorService?: AdvisorProvider;
- protected learnService: LearnService;
protected commandController: CommandController;
protected scanModeService: ScanModeService;
protected ossVulnerabilityCountService: OssVulnerabilityCountService;
@@ -62,7 +60,6 @@ export default abstract class BaseSnykModule implements IBaseSnykModule {
protected notificationService: INotificationService;
protected analytics: IAnalytics;
- protected snykApiClient: ISnykApiClient;
protected advisorApiClient: IAdvisorApiClient;
protected falsePositiveApi: IFalsePositiveApi;
snykCodeOld: ISnykCodeServiceOld;
@@ -75,6 +72,7 @@ export default abstract class BaseSnykModule implements IBaseSnykModule {
readonly loadingBadge: ILoadingBadge;
protected user: User;
protected experimentService: ExperimentService;
+ protected learnService: LearnService;
protected snykCodeErrorHandler: ISnykCodeErrorHandler;
protected markdownStringAdapter: IMarkdownStringAdapter;
@@ -88,8 +86,6 @@ export default abstract class BaseSnykModule implements IBaseSnykModule {
this.contextService = new ContextService();
this.openerService = new OpenerService();
this.loadingBadge = new LoadingBadge();
- this.learnService = new LearnService(configuration, Logger);
- this.snykApiClient = new SnykApiClient(configuration, vsCodeWorkspace, Logger);
this.falsePositiveApi = new FalsePositiveApi(configuration, vsCodeWorkspace, Logger);
this.snykCodeErrorHandler = new SnykCodeErrorHandler(
this.contextService,
@@ -98,7 +94,6 @@ export default abstract class BaseSnykModule implements IBaseSnykModule {
this,
configuration,
);
- this.codeSettings = new CodeSettings(this.snykApiClient, this.contextService, configuration, this.openerService);
this.advisorApiClient = new AdvisorApiClient(configuration, Logger);
this.markdownStringAdapter = new MarkdownStringAdapter();
this.workspaceTrust = new WorkspaceTrust();
diff --git a/src/snyk/base/modules/snykLib.ts b/src/snyk/base/modules/snykLib.ts
index e2c686aa1..d9b2cfa32 100644
--- a/src/snyk/base/modules/snykLib.ts
+++ b/src/snyk/base/modules/snykLib.ts
@@ -11,6 +11,7 @@ import { Logger } from '../../common/logger/logger';
import { vsCodeWorkspace } from '../../common/vscode/workspace';
import BaseSnykModule from './baseSnykModule';
import { ISnykLib } from './interfaces';
+import { vsCodeCommands } from '../../common/vscode/commands';
export default class SnykLib extends BaseSnykModule implements ISnykLib {
private async runFullScan_(manual = false): Promise {
@@ -39,7 +40,7 @@ export default class SnykLib extends BaseSnykModule implements ISnykLib {
const workspacePaths = vsCodeWorkspace.getWorkspaceFolders();
await this.setWorkspaceContext(workspacePaths);
- await this.user.identify(this.snykApiClient, this.analytics);
+ await this.user.identify(vsCodeCommands, this.analytics);
if (workspacePaths.length) {
this.logFullAnalysisIsTriggered(manual);
diff --git a/src/snyk/base/services/authenticationService.ts b/src/snyk/base/services/authenticationService.ts
index b722c2b92..b27f574c4 100644
--- a/src/snyk/base/services/authenticationService.ts
+++ b/src/snyk/base/services/authenticationService.ts
@@ -1,7 +1,8 @@
import { validate as uuidValidate } from 'uuid';
import { IAnalytics } from '../../common/analytics/itly';
import { IConfiguration } from '../../common/configuration/configuration';
-import { DID_CHANGE_CONFIGURATION_METHOD, SNYK_WORKSPACE_SCAN_COMMAND } from '../../common/constants/languageServer';
+import { SNYK_WORKSPACE_SCAN_COMMAND } from '../../common/constants/commands';
+import { DID_CHANGE_CONFIGURATION_METHOD } from '../../common/constants/languageServer';
import { SNYK_CONTEXT } from '../../common/constants/views';
import { ILog } from '../../common/logger/interfaces';
import { IContextService } from '../../common/services/contextService';
@@ -12,11 +13,20 @@ import { IBaseSnykModule } from '../modules/interfaces';
export interface IAuthenticationService {
initiateLogin(): Promise;
+
initiateLogout(): Promise;
+
setToken(): Promise;
+
updateToken(token: string): Promise;
}
+export type OAuthToken = {
+ access_token: string;
+ expiry: string;
+ refresh_token: string;
+};
+
export class AuthenticationService implements IAuthenticationService {
constructor(
private readonly contextService: IContextService,
@@ -45,7 +55,7 @@ export class AuthenticationService implements IAuthenticationService {
placeHolder: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
password: true,
validateInput: token => {
- const valid = uuidValidate(token);
+ const valid = this.validateToken(token);
if (!valid) {
return 'The entered token has an invalid format.';
}
@@ -57,11 +67,29 @@ export class AuthenticationService implements IAuthenticationService {
return await this.clientAdapter.getLanguageClient().sendNotification(DID_CHANGE_CONFIGURATION_METHOD, {});
}
+ validateToken(token: string) {
+ let valid = uuidValidate(token);
+ if (valid) return true;
+
+ // try to parse as json (oauth2 token)
+ try {
+ const oauthToken = JSON.parse(token) as OAuthToken;
+ valid =
+ oauthToken.access_token.length > 0 &&
+ Date.parse(oauthToken.expiry) > Date.now() &&
+ oauthToken.refresh_token.length > 0;
+ this.logger.debug(`Token ${token} parsed`);
+ } catch (e) {
+ this.logger.warn(`Token ${token} is not a valid uuid or json string: ${e}`);
+ }
+ return valid;
+ }
+
async updateToken(token: string): Promise {
if (!token) {
await this.initiateLogout();
} else {
- if (!uuidValidate(token)) return Promise.reject(new Error('The entered token has an invalid format.'));
+ if (!this.validateToken(token)) return Promise.reject(new Error('The entered token has an invalid format.'));
await this.configuration.setToken(token);
await this.contextService.setContext(SNYK_CONTEXT.AUTHENTICATING, false);
diff --git a/src/snyk/cli/process.ts b/src/snyk/cli/process.ts
index 0a99b44c2..d49553ff0 100644
--- a/src/snyk/cli/process.ts
+++ b/src/snyk/cli/process.ts
@@ -5,10 +5,9 @@ import { getVsCodeProxy } from '../common/proxy';
import { IVSCodeWorkspace } from '../common/vscode/workspace';
import { CLI_INTEGRATION_NAME } from './contants/integration';
import { CliError } from './services/cliService';
+import { OAuthToken } from '../base/services/authenticationService';
export class CliProcess {
- private readonly successExitCodes = [0, 1];
-
private runningProcess: ChildProcessWithoutNullStreams | null;
constructor(
@@ -59,7 +58,6 @@ export class CliProcess {
let env = {
SNYK_INTEGRATION_NAME: CLI_INTEGRATION_NAME,
SNYK_INTEGRATION_VERSION: await Configuration.getVersion(),
- SNYK_TOKEN: await this.config.getToken(),
SNYK_API: this.config.snykOssApiEndpoint,
SNYK_CFG_ORG: this.config.organization,
} as NodeJS.ProcessEnv;
@@ -77,6 +75,20 @@ export class CliProcess {
};
}
+ const token = await this.config.getToken();
+ if (token && this.config.snykOssApiEndpoint.indexOf('snykgov.io') > 1) {
+ const oauthToken = JSON.parse(token) as OAuthToken;
+ env = {
+ ...env,
+ SNYK_OAUTH_TOKEN: oauthToken.access_token,
+ };
+ } else {
+ env = {
+ ...env,
+ SNYK_TOKEN: token,
+ };
+ }
+
return env;
}
diff --git a/src/snyk/common/commands/commandController.ts b/src/snyk/common/commands/commandController.ts
index 6e5413b4e..5b146a509 100644
--- a/src/snyk/common/commands/commandController.ts
+++ b/src/snyk/common/commands/commandController.ts
@@ -13,12 +13,13 @@ import { OssIssueCommandArg } from '../../snykOss/views/ossVulnerabilityTreeProv
import { IAnalytics } from '../analytics/itly';
import {
SNYK_INITIATE_LOGIN_COMMAND,
+ SNYK_LOGIN_COMMAND,
SNYK_OPEN_BROWSER_COMMAND,
SNYK_SET_TOKEN_COMMAND,
+ SNYK_TRUST_WORKSPACE_FOLDERS_COMMAND,
VSCODE_GO_TO_SETTINGS_COMMAND,
} from '../constants/commands';
import { COMMAND_DEBOUNCE_INTERVAL, IDE_NAME, SNYK_NAME_EXTENSION, SNYK_PUBLISHER } from '../constants/general';
-import { SNYK_LOGIN_COMMAND, SNYK_TRUST_WORKSPACE_FOLDERS_COMMAND } from '../constants/languageServer';
import { ErrorHandler } from '../error/errorHandler';
import { ILanguageServer } from '../languageServer/languageServer';
import { CodeIssueData, IacIssueData } from '../languageServer/types';
diff --git a/src/snyk/common/constants/commands.ts b/src/snyk/common/constants/commands.ts
index a48a80b57..7dbbb9c19 100644
--- a/src/snyk/common/constants/commands.ts
+++ b/src/snyk/common/constants/commands.ts
@@ -17,6 +17,13 @@ export const SNYK_OPEN_ISSUE_COMMAND = 'snyk.showissue';
export const SNYK_IGNORE_ISSUE_COMMAND = 'snyk.ignoreissue';
export const SNYK_SHOW_OUTPUT_COMMAND = 'snyk.showOutputChannel';
export const SNYK_SHOW_LS_OUTPUT_COMMAND = 'snyk.showLsOutputChannel';
+export const SNYK_GET_LESSON_COMMAND = 'snyk.getLearnLesson';
+export const SNYK_GET_SETTINGS_SAST_ENABLED = 'snyk.getSettingsSastEnabled';
+// commands
+export const SNYK_LOGIN_COMMAND = 'snyk.login';
+export const SNYK_WORKSPACE_SCAN_COMMAND = 'snyk.workspace.scan';
+export const SNYK_TRUST_WORKSPACE_FOLDERS_COMMAND = 'snyk.trustWorkspaceFolders';
+export const SNYK_GET_ACTIVE_USER = 'snyk.getActiveUser';
// custom Snyk constants used in commands
export const SNYK_CONTEXT_PREFIX = 'snyk:';
diff --git a/src/snyk/common/constants/languageServer.ts b/src/snyk/common/constants/languageServer.ts
index dccb76fe3..94230e378 100644
--- a/src/snyk/common/constants/languageServer.ts
+++ b/src/snyk/common/constants/languageServer.ts
@@ -2,7 +2,7 @@
// Language Server name, used e.g. for the output channel
export const SNYK_LANGUAGE_SERVER_NAME = 'Snyk Language Server';
// The internal language server protocol version for custom messages and configuration
-export const PROTOCOL_VERSION = 9;
+export const PROTOCOL_VERSION = 10;
// LS protocol methods (needed for not having to rely on vscode dependencies in testing)
export const DID_CHANGE_CONFIGURATION_METHOD = 'workspace/didChangeConfiguration';
@@ -12,8 +12,3 @@ 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';
-
-// commands
-export const SNYK_LOGIN_COMMAND = 'snyk.login';
-export const SNYK_WORKSPACE_SCAN_COMMAND = 'snyk.workspace.scan';
-export const SNYK_TRUST_WORKSPACE_FOLDERS_COMMAND = 'snyk.trustWorkspaceFolders';
diff --git a/src/snyk/common/services/cliConfigService.ts b/src/snyk/common/services/cliConfigService.ts
deleted file mode 100644
index 8f2f9b600..000000000
--- a/src/snyk/common/services/cliConfigService.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ISnykApiClient } from '../api/apiСlient';
-import { Configuration, IConfiguration } from '../configuration/configuration';
-
-export type SastSettings = {
- sastEnabled: boolean;
- localCodeEngine: {
- enabled: boolean;
- };
- reportFalsePositivesEnabled: boolean;
-};
-
-export async function getSastSettings(api: ISnykApiClient, config: IConfiguration): Promise {
- const response = await api.get('cli-config/settings/sast', {
- headers: {
- 'x-snyk-ide': `${Configuration.source}-${await Configuration.getVersion()}`,
- },
- params: {
- ...(config.organization ? { org: config.organization } : {}),
- },
- });
-
- if (!response) return;
-
- return response.data;
-}
diff --git a/src/snyk/common/services/learnService.ts b/src/snyk/common/services/learnService.ts
index 740ba2ee8..45fcf8a6c 100644
--- a/src/snyk/common/services/learnService.ts
+++ b/src/snyk/common/services/learnService.ts
@@ -1,146 +1,62 @@
-import axios from 'axios';
-import { isCodeIssue, isCodeIssueOld, isOssIssue, OpenCommandIssueType } from '../../common/commands/types';
-import { SNYK_LEARN_API_CACHE_DURATION_IN_MS } from '../../common/constants/general';
-import type { completeFileSuggestionType } from '../../snykCode/interfaces';
+import { completeFileSuggestionType } from '../../snykCode/interfaces';
import { OssIssueCommandArg } from '../../snykOss/views/ossVulnerabilityTreeProvider';
-import { IConfiguration } from '../configuration/configuration';
-import { ErrorHandler } from '../error/errorHandler';
import { CodeIssueData, Issue } from '../languageServer/types';
-import { ILog } from '../logger/interfaces';
+import { SNYK_GET_LESSON_COMMAND } from '../constants/commands';
+import { IVSCodeCommands } from '../vscode/commands';
export type Lesson = {
- title: string;
- lessonId: string;
- ecosystem: string;
url: string;
+ title: string;
};
-interface LessonLookupParams {
- rule: string;
- ecosystem: string;
- cwes?: string[];
- cves?: string[];
-}
-
export class LearnService {
- private lessonsCache = new Map<
- string,
- {
- lessons: Lesson[];
- expiry: number;
- }
- >();
-
- constructor(
- private readonly configuration: IConfiguration,
- private readonly logger: ILog,
- private readonly shouldCacheRequests = true,
- ) {}
-
- // TODO: remove when Code results come from LS
- static getCodeIssueParamsOld(issue: completeFileSuggestionType): LessonLookupParams {
- const idParts = issue.id.split(/\/|%2F/g);
-
- return {
- rule: idParts[idParts.length - 1],
- ecosystem: idParts[0],
- cwes: issue.cwe,
- };
- }
-
- static getCodeIssueParams(issue: Issue): LessonLookupParams {
- const idParts = issue.additionalData.ruleId.split(/\/|%2F/g);
-
- return {
- rule: idParts[idParts.length - 1],
- ecosystem: idParts[0],
- cwes: issue.additionalData.cwe,
- };
- }
+ constructor(private commandExecutor: IVSCodeCommands) {}
- static getOSSIssueParams(issue: OssIssueCommandArg): LessonLookupParams {
- return {
- rule: issue.id,
- ecosystem: issue.packageManager,
- cwes: issue.identifiers?.CWE,
- cves: issue.identifiers?.CVE,
- };
- }
-
- async requestLessons(params: LessonLookupParams) {
- const cacheResult = this.lessonsCache.get(params.rule);
-
- if (this.shouldCacheRequests && cacheResult && cacheResult?.expiry > Date.now()) {
- return cacheResult.lessons;
- } else {
- const res = await axios.get<{ lessons: Lesson[] }>('/lessons/lookup-for-cta', {
- baseURL: this.snykLearnEndpoint,
- params: {
- source: 'ide',
- rule: params.rule,
- ecosystem: params.ecosystem,
- cwe: params.cwes?.[0],
- cve: params.cves?.[0],
- },
- });
-
- const lessons = res.data.lessons;
-
- this.lessonsCache.set(params.rule, {
- lessons,
- expiry: Date.now() + SNYK_LEARN_API_CACHE_DURATION_IN_MS,
- });
+ async getOssLesson(vulnerability: OssIssueCommandArg): Promise {
+ const cwe = vulnerability.identifiers?.CWE;
+ let cweElement = '';
+ if (cwe && cwe.length > 0) {
+ cweElement = cwe[0];
+ }
- return lessons;
+ const cve = vulnerability.identifiers?.CWE;
+ let cveElement = '';
+ if (cve && cve.length > 0) {
+ cveElement = cve[0];
}
+ return this.commandExecutor.executeCommand(
+ SNYK_GET_LESSON_COMMAND,
+ vulnerability.id,
+ vulnerability.packageManager,
+ cweElement,
+ cveElement,
+ 4,
+ );
}
- async getLesson(
- issue: OssIssueCommandArg | completeFileSuggestionType | Issue,
- issueType: OpenCommandIssueType,
- ): Promise {
- try {
- let params: LessonLookupParams | null = null;
-
- if (isCodeIssueOld(issue, issueType)) {
- if (!issue.isSecurityType) return null;
-
- params = LearnService.getCodeIssueParamsOld(issue);
- } else if (isCodeIssue(issue, issueType)) {
- if (!issue.additionalData.isSecurityType) return null;
-
- params = LearnService.getCodeIssueParams(issue);
- } else if (isOssIssue(issue, issueType)) {
- // Snyk Learn does not currently deal with licensing issues.
- if (issue.license) return null;
+ async getCodeLesson(issue: Issue): Promise {
+ const ruleSplit = issue.additionalData.ruleId.split('/');
+ const rule = ruleSplit[ruleSplit.length - 1];
+ const ecosystem = ruleSplit[0];
+ const additionalData = issue.additionalData;
+ let cwe = '';
+ if (additionalData.cwe.length > 0) {
+ cwe = additionalData.cwe[0];
+ }
- params = LearnService.getOSSIssueParams(issue);
- } else {
- ErrorHandler.handle(new Error(`Issue type "${issueType}" not supported`), this.logger);
- return null;
- }
+ return this.commandExecutor.executeCommand(SNYK_GET_LESSON_COMMAND, rule, ecosystem, cwe, '', 2);
+ }
- if (!params) {
- return null;
- }
+ async getCodeLessonOld(issue: completeFileSuggestionType): Promise {
+ const ruleSplit = issue.id.split('/');
+ const rule = ruleSplit[ruleSplit.length - 1];
+ const ecosystem = ruleSplit[0];
- const lessons = await this.requestLessons(params);
- if (!lessons.length) {
- return null;
- } else {
- const lesson = lessons[0];
- const lessonURL = new URL(lesson.url);
- lessonURL.searchParams.set('loc', 'ide');
- return { ...lesson, url: lessonURL.toString() };
- }
- return lessons.length > 0 ? lessons[0] : null;
- } catch (err) {
- ErrorHandler.handle(err, this.logger, 'Error getting Snyk Learn Lesson');
- return null;
+ let cwe = '';
+ if (issue.cwe.length > 0) {
+ cwe = issue.cwe[0];
}
- }
- get snykLearnEndpoint(): string {
- return `${this.configuration.baseApiUrl}/v1/learn`;
+ return this.commandExecutor.executeCommand(SNYK_GET_LESSON_COMMAND, rule, ecosystem, cwe, '', 2);
}
}
diff --git a/src/snyk/common/user.ts b/src/snyk/common/user.ts
index 386c040d9..e6b49a5c8 100644
--- a/src/snyk/common/user.ts
+++ b/src/snyk/common/user.ts
@@ -1,10 +1,12 @@
import * as crypto from 'crypto';
import { v4 as uuidv4 } from 'uuid';
import { IAnalytics } from './analytics/itly';
-import { ISnykApiClient } from './api/apiСlient';
+import { SNYK_GET_ACTIVE_USER } from './constants/commands';
import { MEMENTO_ANONYMOUS_ID } from './constants/globalState';
import { ErrorReporter } from './error/errorReporter';
+import { IVSCodeCommands } from './vscode/commands';
import { ExtensionContext } from './vscode/extensionContext';
+import { ILog } from './logger/interfaces';
export type UserDto = {
id: string;
@@ -13,22 +15,24 @@ export type UserDto = {
export class User {
private _authenticatedId?: string;
+ private logger?: ILog;
readonly anonymousId: string;
- constructor(anonymousId?: string, authenticatedId?: string) {
+ constructor(anonymousId?: string, authenticatedId?: string, logger?: ILog) {
this.anonymousId = anonymousId ?? uuidv4();
this._authenticatedId = authenticatedId ?? undefined;
+ this.logger = logger ?? undefined;
}
- static async getAnonymous(context: ExtensionContext): Promise {
+ static async getAnonymous(context: ExtensionContext, logger?: ILog): Promise {
let anonymousId = context.getGlobalStateValue(MEMENTO_ANONYMOUS_ID);
if (!anonymousId) {
anonymousId = uuidv4();
await context.updateGlobalStateValue(MEMENTO_ANONYMOUS_ID, anonymousId);
}
- return new User(anonymousId);
+ return new User(anonymousId, undefined, logger ?? undefined);
}
get authenticatedId(): string | undefined {
@@ -43,8 +47,8 @@ export class User {
return crypto.createHash('sha256').update(this._authenticatedId).digest('hex');
}
- async identify(apiClient: ISnykApiClient, analytics: IAnalytics): Promise {
- const user = await this.userMe(apiClient);
+ async identify(commandExecutor: IVSCodeCommands, analytics: IAnalytics): Promise {
+ const user = await this.userMe(commandExecutor);
if (user && user.id) {
this._authenticatedId = user.id;
@@ -53,10 +57,15 @@ export class User {
}
}
- private async userMe(api: ISnykApiClient): Promise {
- const response = await api.get('/user/me');
- if (!response) return;
-
- return response.data;
+ private async userMe(commandExecutor: IVSCodeCommands): Promise {
+ let user: UserDto | undefined;
+ try {
+ user = await commandExecutor.executeCommand(SNYK_GET_ACTIVE_USER);
+ } catch (error) {
+ if (this.logger) {
+ this.logger.error(`Failed to get user: ${error}`);
+ }
+ }
+ return user;
}
}
diff --git a/src/snyk/common/vscode/commands.ts b/src/snyk/common/vscode/commands.ts
index c3ee56fa8..ad29c18ee 100644
--- a/src/snyk/common/vscode/commands.ts
+++ b/src/snyk/common/vscode/commands.ts
@@ -10,4 +10,4 @@ export class VSCodeCommands implements IVSCodeCommands {
}
}
-export const vsCodeComands = new VSCodeCommands();
+export const vsCodeCommands = new VSCodeCommands();
diff --git a/src/snyk/extension.ts b/src/snyk/extension.ts
index 20de891ef..027457850 100644
--- a/src/snyk/extension.ts
+++ b/src/snyk/extension.ts
@@ -27,9 +27,9 @@ import {
SNYK_SHOW_LS_OUTPUT_COMMAND,
SNYK_SHOW_OUTPUT_COMMAND,
SNYK_START_COMMAND,
+ SNYK_WORKSPACE_SCAN_COMMAND,
} from './common/constants/commands';
import { MEMENTO_FIRST_INSTALL_DATE_KEY } from './common/constants/globalState';
-import { SNYK_WORKSPACE_SCAN_COMMAND } from './common/constants/languageServer';
import {
SNYK_CONTEXT,
SNYK_VIEW_ANALYSIS_CODE_ENABLEMENT,
@@ -51,10 +51,11 @@ import { LanguageServer } from './common/languageServer/languageServer';
import { StaticLsApi } from './common/languageServer/staticLsApi';
import { Logger } from './common/logger/logger';
import { DownloadService } from './common/services/downloadService';
+import { LearnService } from './common/services/learnService';
import { NotificationService } from './common/services/notificationService';
import { User } from './common/user';
import { CodeActionAdapter, CodeActionKindAdapter } from './common/vscode/codeAction';
-import { vsCodeComands } from './common/vscode/commands';
+import { vsCodeCommands } from './common/vscode/commands';
import { vsCodeEnv } from './common/vscode/env';
import { extensionContext } from './common/vscode/extensionContext';
import { HoverAdapter } from './common/vscode/hover';
@@ -70,6 +71,7 @@ import ConfigurationWatcher from './common/watchers/configurationWatcher';
import { IgnoreCommand } from './snykCode/codeActions/ignoreCommand';
import { SnykCodeService } from './snykCode/codeService';
import { SnykCodeServiceOld } from './snykCode/codeServiceOld';
+import { CodeSettings } from './snykCode/codeSettings';
import { CodeQualityIssueTreeProvider } from './snykCode/views/qualityIssueTreeProvider';
import { CodeQualityIssueTreeProviderOld } from './snykCode/views/qualityIssueTreeProviderOld';
import CodeSecurityIssueTreeProvider from './snykCode/views/securityIssueTreeProvider';
@@ -114,7 +116,7 @@ class SnykExtension extends SnykLib implements IExtension {
}
private async initializeExtension(vscodeContext: vscode.ExtensionContext, snykConfiguration?: SnykConfiguration) {
- this.user = await User.getAnonymous(this.context);
+ this.user = await User.getAnonymous(this.context, Logger);
this.analytics = new Iteratively(
this.user,
@@ -129,7 +131,7 @@ class SnykExtension extends SnykLib implements IExtension {
this.configurationWatcher = new ConfigurationWatcher(this.analytics, Logger);
this.notificationService = new NotificationService(
vsCodeWindow,
- vsCodeComands,
+ vsCodeCommands,
configuration,
this.analytics,
Logger,
@@ -146,9 +148,13 @@ class SnykExtension extends SnykLib implements IExtension {
this.analytics,
Logger,
languageClientAdapter,
- vsCodeComands,
+ vsCodeCommands,
);
+ this.learnService = new LearnService(vsCodeCommands);
+
+ this.codeSettings = new CodeSettings(this.contextService, configuration, this.openerService, vsCodeCommands);
+
this.snykCodeOld = new SnykCodeServiceOld(
this.context,
configuration,
@@ -162,10 +168,9 @@ class SnykExtension extends SnykLib implements IExtension {
new VSCodeLanguages(),
this.snykCodeErrorHandler,
new UriAdapter(),
- this.codeSettings,
- this.learnService,
this.markdownStringAdapter,
this.workspaceTrust,
+ this.learnService,
);
this.scanModeService = new ScanModeService(this.contextService, configuration, this.analytics);
@@ -263,7 +268,7 @@ class SnykExtension extends SnykLib implements IExtension {
this.ossService,
this.scanModeService,
vsCodeWorkspace,
- vsCodeComands,
+ vsCodeCommands,
vsCodeWindow,
this.languageServer,
Logger,
diff --git a/src/snyk/snykCode/codeServiceOld.ts b/src/snyk/snykCode/codeServiceOld.ts
index 47a152edb..20269e903 100644
--- a/src/snyk/snykCode/codeServiceOld.ts
+++ b/src/snyk/snykCode/codeServiceOld.ts
@@ -10,7 +10,6 @@ import { ErrorHandler } from '../common/error/errorHandler';
import { ILog } from '../common/logger/interfaces';
import { Logger } from '../common/logger/logger';
import { messages as generalAnalysisMessages } from '../common/messages/analysisMessages';
-import { LearnService } from '../common/services/learnService';
import { IViewManagerService } from '../common/services/viewManagerService';
import { User } from '../common/user';
import { IWebViewProvider } from '../common/views/webviewProvider';
@@ -25,7 +24,6 @@ import { IVSCodeWorkspace } from '../common/vscode/workspace';
import SnykCodeAnalyzer from './analyzer/analyzer';
import { Progress } from './analyzer/progress';
import { DisposableCodeActionsProvider } from './codeActions/disposableCodeActionsProvider';
-import { ICodeSettings } from './codeSettings';
import { ISnykCodeErrorHandler } from './error/snykCodeErrorHandler';
import { IFalsePositiveApi } from './falsePositive/api/falsePositiveApi';
import { FalsePositive } from './falsePositive/falsePositive';
@@ -39,6 +37,7 @@ import {
} from './views/falsePositive/falsePositiveWebviewProvider';
import { ICodeSuggestionWebviewProviderOld } from './views/interfaces';
import { CodeSuggestionWebviewProviderOld } from './views/suggestion/codeSuggestionWebviewProviderOld';
+import { LearnService } from '../common/services/learnService';
export interface ISnykCodeServiceOld extends AnalysisStatusProvider, Disposable {
analyzer: ISnykCodeAnalyzer;
@@ -91,10 +90,9 @@ export class SnykCodeServiceOld extends AnalysisStatusProvider implements ISnykC
readonly languages: IVSCodeLanguages,
private readonly errorHandler: ISnykCodeErrorHandler,
private readonly uriAdapter: IUriAdapter,
- codeSettings: ICodeSettings,
- private readonly learnService: LearnService,
private readonly markdownStringAdapter: IMarkdownStringAdapter,
private readonly workspaceTrust: IWorkspaceTrust,
+ private readonly learnService: LearnService,
) {
super();
this.analyzer = new SnykCodeAnalyzer(
@@ -123,7 +121,6 @@ export class SnykCodeServiceOld extends AnalysisStatusProvider implements ISnykC
this.logger,
languages,
workspace,
- codeSettings,
this.learnService,
);
@@ -190,7 +187,7 @@ export class SnykCodeServiceOld extends AnalysisStatusProvider implements ISnykC
},
};
- let result: FileAnalysis | null = null;
+ let result: FileAnalysis | null;
if (this.changedFiles.size && this.remoteBundle) {
const changedFiles = [...this.changedFiles];
result = await extendAnalysis({
diff --git a/src/snyk/snykCode/codeSettings.ts b/src/snyk/snykCode/codeSettings.ts
index 08064bd1b..e864675e0 100644
--- a/src/snyk/snykCode/codeSettings.ts
+++ b/src/snyk/snykCode/codeSettings.ts
@@ -1,18 +1,28 @@
-import { ISnykApiClient } from '../common/api/apiСlient';
import { IConfiguration } from '../common/configuration/configuration';
+import { SNYK_GET_SETTINGS_SAST_ENABLED } from '../common/constants/commands';
import { SNYK_CONTEXT } from '../common/constants/views';
-import { getSastSettings, SastSettings } from '../common/services/cliConfigService';
import { IContextService } from '../common/services/contextService';
import { IOpenerService } from '../common/services/openerService';
+import { IVSCodeCommands } from '../common/vscode/commands';
export interface ICodeSettings {
reportFalsePositivesEnabled: boolean;
checkCodeEnabled(): Promise;
+
enable(): Promise;
+
getSastSettings(): Promise;
}
+export type SastSettings = {
+ sastEnabled: boolean;
+ localCodeEngine: {
+ enabled: boolean;
+ };
+ reportFalsePositivesEnabled: boolean;
+};
+
export class CodeSettings implements ICodeSettings {
private _reportFalsePositivesEnabled: boolean;
@@ -21,34 +31,44 @@ export class CodeSettings implements ICodeSettings {
}
constructor(
- private readonly snykApiClient: ISnykApiClient,
private readonly contextService: IContextService,
private readonly config: IConfiguration,
private readonly openerService: IOpenerService,
+ private readonly commandExecutor: IVSCodeCommands,
) {}
async checkCodeEnabled(): Promise {
- const settings = await this.getSastSettings();
- if (!settings) {
- return false;
+ let codeEnabled = false;
+ let localCodeEngineEnabled = false;
+ try {
+ const settings = await this.getSastSettings();
+ if (!settings) {
+ return false;
+ }
+ codeEnabled = settings.sastEnabled && !settings.localCodeEngine.enabled;
+ localCodeEngineEnabled = settings.localCodeEngine.enabled;
+ } catch (e) {
+ // Ignore potential command not found error during LS startup and poll
+ codeEnabled = await this.enable(false);
}
-
- await this.contextService.setContext(SNYK_CONTEXT.CODE_ENABLED, settings.sastEnabled);
- await this.contextService.setContext(
- SNYK_CONTEXT.CODE_LOCAL_ENGINE_ENABLED,
- settings.localCodeEngine.enabled ?? false,
- );
-
- return settings.sastEnabled && !settings.localCodeEngine.enabled;
+ await this.contextService.setContext(SNYK_CONTEXT.CODE_ENABLED, codeEnabled);
+ await this.contextService.setContext(SNYK_CONTEXT.CODE_LOCAL_ENGINE_ENABLED, localCodeEngineEnabled);
+ return codeEnabled;
}
- async enable(): Promise {
- let settings = await this.getSastSettings();
+ async enable(openBrowser = true): Promise {
+ let settings: SastSettings | undefined;
+ try {
+ settings = await this.getSastSettings();
+ } catch (e) {
+ // Ignore potential command not found error during LS startup
+ }
+
if (settings?.sastEnabled) {
return true;
}
- if (this.config.snykCodeUrl != null) {
+ if (this.config.snykCodeUrl != null && openBrowser) {
await this.openerService.openBrowserUrl(this.config.snykCodeUrl);
}
@@ -57,10 +77,14 @@ export class CodeSettings implements ICodeSettings {
// eslint-disable-next-line no-await-in-loop
await this.sleep(i * 1000);
- // eslint-disable-next-line no-await-in-loop
- settings = await this.getSastSettings();
- if (settings?.sastEnabled) {
- return true;
+ try {
+ // eslint-disable-next-line no-await-in-loop
+ settings = await this.getSastSettings();
+ if (settings?.sastEnabled && !settings?.localCodeEngine.enabled) {
+ return true;
+ }
+ } catch (e) {
+ // Ignore potential command not found error during LS startup
}
}
@@ -68,13 +92,7 @@ export class CodeSettings implements ICodeSettings {
}
async getSastSettings(): Promise {
- const settings = await getSastSettings(this.snykApiClient, this.config);
- if (settings) {
- // cache if false positive reports are enabled.
- this._reportFalsePositivesEnabled = settings.reportFalsePositivesEnabled;
- }
-
- return settings;
+ return this.commandExecutor.executeCommand(SNYK_GET_SETTINGS_SAST_ENABLED);
}
private sleep = (duration: number) => new Promise(resolve => setTimeout(resolve, duration));
diff --git a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts
index 9e1197ed8..8ab86d1f3 100644
--- a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts
+++ b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts
@@ -1,6 +1,5 @@
import _ from 'lodash';
import * as vscode from 'vscode';
-import { OpenCommandIssueType } from '../../../common/commands/types';
import {
SNYK_IGNORE_ISSUE_COMMAND,
SNYK_OPEN_BROWSER_COMMAND,
@@ -11,7 +10,6 @@ import { ErrorHandler } from '../../../common/error/errorHandler';
import { CodeIssueData, ExampleCommitFix, Issue, Marker, Point } from '../../../common/languageServer/types';
import { ILog } from '../../../common/logger/interfaces';
import { messages as learnMessages } from '../../../common/messages/learn';
-import { LearnService } from '../../../common/services/learnService';
import { getNonce } from '../../../common/views/nonce';
import { WebviewPanelSerializer } from '../../../common/views/webviewPanelSerializer';
import { WebviewProvider } from '../../../common/views/webviewProvider';
@@ -24,6 +22,7 @@ import { messages as errorMessages } from '../../messages/error';
import { getAbsoluteMarkerFilePath } from '../../utils/analysisUtils';
import { IssueUtils } from '../../utils/issueUtils';
import { ICodeSuggestionWebviewProvider } from '../interfaces';
+import { LearnService } from '../../../common/services/learnService';
type Suggestion = {
id: string;
@@ -75,7 +74,7 @@ export class CodeSuggestionWebviewProvider
async postLearnLessonMessage(issue: Issue): Promise {
try {
if (this.panel) {
- const lesson = await this.learnService.getLesson(issue, OpenCommandIssueType.CodeIssue);
+ const lesson = await this.learnService.getCodeLesson(issue);
if (lesson) {
void this.panel.webview.postMessage({
type: 'setLesson',
diff --git a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProviderOld.ts b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProviderOld.ts
index bbde0cc6e..b78996d73 100644
--- a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProviderOld.ts
+++ b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProviderOld.ts
@@ -1,5 +1,4 @@
import * as vscode from 'vscode';
-import { OpenCommandIssueType } from '../../../common/commands/types';
import { IConfiguration } from '../../../common/configuration/configuration';
import {
SNYK_IGNORE_ISSUE_COMMAND,
@@ -18,7 +17,6 @@ import { ExtensionContext } from '../../../common/vscode/extensionContext';
import { IVSCodeLanguages } from '../../../common/vscode/languages';
import { IVSCodeWindow } from '../../../common/vscode/window';
import { IVSCodeWorkspace } from '../../../common/vscode/workspace';
-import { ICodeSettings } from '../../codeSettings';
import { WEBVIEW_PANEL_QUALITY_TITLE, WEBVIEW_PANEL_SECURITY_TITLE } from '../../constants/analysis';
import { completeFileSuggestionType, ISnykCodeAnalyzer } from '../../interfaces';
import { messages as errorMessages } from '../../messages/error';
@@ -41,7 +39,6 @@ export class CodeSuggestionWebviewProviderOld
protected readonly logger: ILog,
private readonly languages: IVSCodeLanguages,
private readonly workspace: IVSCodeWorkspace,
- private readonly codeSettings: ICodeSettings,
private readonly learnService: LearnService,
) {
super(context, logger);
@@ -72,7 +69,7 @@ export class CodeSuggestionWebviewProviderOld
async postLearnLessonMessage(suggestion: completeFileSuggestionType): Promise {
try {
if (this.panel) {
- const lesson = await this.learnService.getLesson(suggestion, OpenCommandIssueType.CodeIssueOld);
+ const lesson = await this.learnService.getCodeLessonOld(suggestion);
if (lesson) {
void this.panel.webview.postMessage({
type: 'setLesson',
diff --git a/src/snyk/snykOss/views/suggestion/ossSuggestionWebviewProvider.ts b/src/snyk/snykOss/views/suggestion/ossSuggestionWebviewProvider.ts
index 3c4df0df2..7173ac675 100644
--- a/src/snyk/snykOss/views/suggestion/ossSuggestionWebviewProvider.ts
+++ b/src/snyk/snykOss/views/suggestion/ossSuggestionWebviewProvider.ts
@@ -1,11 +1,9 @@
import * as vscode from 'vscode';
-import { OpenCommandIssueType } from '../../../common/commands/types';
import { SNYK_OPEN_BROWSER_COMMAND } from '../../../common/constants/commands';
import { SNYK_VIEW_SUGGESTION_OSS } from '../../../common/constants/views';
import { ErrorHandler } from '../../../common/error/errorHandler';
import { ILog } from '../../../common/logger/interfaces';
import { messages as learnMessages } from '../../../common/messages/learn';
-import { LearnService } from '../../../common/services/learnService';
import { getNonce } from '../../../common/views/nonce';
import { WebviewPanelSerializer } from '../../../common/views/webviewPanelSerializer';
import { WebviewProvider } from '../../../common/views/webviewProvider';
@@ -13,6 +11,7 @@ import { ExtensionContext } from '../../../common/vscode/extensionContext';
import { IVSCodeWindow } from '../../../common/vscode/window';
import { messages as errorMessages } from '../../messages/error';
import { OssIssueCommandArg } from '../ossVulnerabilityTreeProvider';
+import { LearnService } from '../../../common/services/learnService';
enum OssSuggestionsViewEventMessageType {
OpenBrowser = 'openBrowser',
@@ -42,7 +41,7 @@ export class OssSuggestionWebviewProvider extends WebviewProvider {
try {
if (this.panel) {
- const lesson = await this.learnService.getLesson(vulnerability, OpenCommandIssueType.OssVulnerability);
+ const lesson = await this.learnService.getOssLesson(vulnerability);
if (lesson) {
void this.panel.webview.postMessage({
type: 'setLesson',
diff --git a/src/test/unit/advisor/services/advisorProvider.test.ts b/src/test/unit/advisor/services/advisorProvider.test.ts
deleted file mode 100644
index d2299138f..000000000
--- a/src/test/unit/advisor/services/advisorProvider.test.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { notStrictEqual, strictEqual } from 'assert';
-import AdvisorProvider from '../../../../snyk/advisor/services/advisorProvider';
-import { ImportedModule } from '../../../../snyk/common/types';
-import { LoggerMock } from '../../mocks/logger.mock';
-import { advisorApiClientStub, postFake } from './advisorStubs';
-
-suite('Advisor score provider.', () => {
- let advisorProvider: AdvisorProvider;
-
- const sampleFilePath = 'C:\\git\\project\\test.js';
- const sampleModuleName = 'mongo-express';
- const sampleImportedModule = {
- fileName: sampleFilePath,
- name: sampleModuleName,
- string: 'const x = require("mongo-express")',
- line: 1,
- loc: {
- start: {
- line: 1,
- column: 16,
- },
- end: {
- line: 1,
- column: 29,
- },
- },
- } as ImportedModule;
-
- const loggerMock = new LoggerMock();
- setup(() => {
- advisorProvider = new AdvisorProvider(advisorApiClientStub, loggerMock);
- });
-
- test('AdvisorProvider returns scores', async () => {
- const scores = await advisorProvider.getScores([sampleImportedModule]);
-
- notStrictEqual(scores, []);
- strictEqual(postFake.returned({ data: [] }), true);
- });
-});
diff --git a/src/test/unit/advisor/services/advisorService.test.ts b/src/test/unit/advisor/services/advisorService.test.ts
deleted file mode 100644
index 870bedb13..000000000
--- a/src/test/unit/advisor/services/advisorService.test.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-import { strictEqual } from 'assert';
-import sinon from 'sinon';
-import AdvisorProvider from '../../../../snyk/advisor/services/advisorProvider';
-import { AdvisorService } from '../../../../snyk/advisor/services/advisorService';
-import { IConfiguration } from '../../../../snyk/common/configuration/configuration';
-import { PJSON } from '../../../../snyk/common/constants/languageConsts';
-import { HoverAdapter } from '../../../../snyk/common/vscode/hover';
-import { IMarkdownStringAdapter } from '../../../../snyk/common/vscode/markdownString';
-import { ThemeColorAdapter } from '../../../../snyk/common/vscode/theme';
-import { TextDocument, TextDocumentChangeEvent, TextEditor } from '../../../../snyk/common/vscode/types';
-import { LoggerMock } from '../../mocks/logger.mock';
-import { advisorApiClientStub, advisorStubLanguages, advisorStubWindow, advisorStubWorkspace } from './advisorStubs';
-
-suite('Advisor AdvisorService', () => {
- let advisorService: AdvisorService;
- let advisorProvider: AdvisorProvider;
-
- const loggerMock = new LoggerMock();
-
- setup(() => {
- advisorProvider = new AdvisorProvider(advisorApiClientStub, loggerMock);
- advisorProvider.getScores = sinon.fake.returns([]);
- advisorService = new AdvisorService(
- advisorStubWindow,
- advisorStubLanguages,
- advisorProvider,
- loggerMock,
- advisorStubWorkspace,
- advisorApiClientStub,
- {} as ThemeColorAdapter,
- {} as HoverAdapter,
- {} as IMarkdownStringAdapter,
- {
- getAdditionalCliParameters: () => undefined,
- getPreviewFeatures: () => {
- return {
- advisor: true,
- };
- },
- } as unknown as IConfiguration,
- );
- });
-
- teardown(() => {
- sinon.restore();
- });
-
- test('Attaches onDidChangeTextDocument listener on activation', async () => {
- advisorStubWindow.onDidChangeActiveTextEditor = sinon.fake();
- const onDidChangeTextDocumentSpy = sinon.fake();
- advisorStubWorkspace.onDidChangeTextDocument = onDidChangeTextDocumentSpy;
-
- await advisorService.activate();
-
- strictEqual(onDidChangeTextDocumentSpy.calledOnce, true);
- });
-
- test('Attaches onDidChangeActiveTextEditor listener on activation', async () => {
- advisorStubWorkspace.onDidChangeTextDocument = sinon.fake();
-
- const onDidChangeActiveTextEditor = sinon.fake();
- advisorStubWindow.onDidChangeActiveTextEditor = onDidChangeActiveTextEditor;
-
- await advisorService.activate();
-
- strictEqual(onDidChangeActiveTextEditor.calledOnce, true);
- });
-
- test('Processes file if active editor is opened on activation', async () => {
- advisorStubWindow.getActiveTextEditor = () =>
- ({
- document: {
- fileName: 'package.json',
- languageId: PJSON,
- getText: () => ``,
- },
- } as unknown as TextEditor);
-
- advisorStubWorkspace.onDidChangeTextDocument = sinon.fake();
- advisorStubWindow.onDidChangeActiveTextEditor = sinon.fake();
-
- const getActiveTextEditorSpy = sinon.spy(advisorStubWindow, 'getActiveTextEditor');
- const processFileSpy = sinon.spy(advisorService, 'processScores');
-
- await advisorService.activate();
-
- strictEqual(getActiveTextEditorSpy.called, true);
- strictEqual(processFileSpy.calledOnce, true);
- });
-
- test("Doesn't process if file is language not supported", async () => {
- const document = {
- fileName: 'C:\\git\\project\\test.java',
- languageId: 'java',
- } as TextDocument;
- const ev: TextDocumentChangeEvent = {
- document,
- contentChanges: [],
- reason: undefined,
- };
-
- const processFileSpy = sinon.spy(advisorService, 'processScores');
- await advisorService.handleEditorEvent(ev.document);
-
- strictEqual(processFileSpy.called, false);
- });
-});
diff --git a/src/test/unit/advisor/services/advisorStubs.ts b/src/test/unit/advisor/services/advisorStubs.ts
deleted file mode 100644
index 3720f5d96..000000000
--- a/src/test/unit/advisor/services/advisorStubs.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import sinon from 'sinon';
-import { AdvisorRegistry } from '../../../../snyk/advisor/advisorTypes';
-import { IAdvisorApiClient } from '../../../../snyk/advisor/services/advisorApiClient';
-import { PJSON } from '../../../../snyk/common/constants/languageConsts';
-import { IVSCodeLanguages } from '../../../../snyk/common/vscode/languages';
-import { TextEditor } from '../../../../snyk/common/vscode/types';
-import { IVSCodeWindow } from '../../../../snyk/common/vscode/window';
-import { IVSCodeWorkspace } from '../../../../snyk/common/vscode/workspace';
-
-const postFake = sinon.stub().returns({
- data: [],
-});
-const scoresStub = sinon.stub().resolves({ data: [] });
-const advisorApiClientStub: IAdvisorApiClient = {
- post: postFake,
- apiPath: '',
- getAdvisorUrl: function (registry: AdvisorRegistry): string {
- return `${registry}/scores`;
- },
-};
-
-const advisorStubWorkspace: IVSCodeWorkspace = {} as IVSCodeWorkspace;
-const advisorStubWindow: IVSCodeWindow = {
- createTextEditorDecorationType: sinon.fake(),
- getActiveTextEditor: sinon.fake.returns({
- document: {
- fileName: 'C:\\git\\project\\package.json',
- languageId: PJSON,
- getText: () => '',
- },
- } as TextEditor),
- getVisibleTextEditors: sinon.fake.returns([]),
-} as unknown as IVSCodeWindow;
-const advisorStubLanguages: IVSCodeLanguages = {
- createDiagnosticCollection: sinon.fake(),
- registerCodeActionsProvider: sinon.fake(),
- registerHoverProvider: sinon.fake(),
-} as unknown as IVSCodeLanguages;
-
-export { scoresStub, postFake, advisorApiClientStub, advisorStubWorkspace, advisorStubLanguages, advisorStubWindow };
diff --git a/src/test/unit/base/services/authenticationService.test.ts b/src/test/unit/base/services/authenticationService.test.ts
index 51325e198..51bd29a84 100644
--- a/src/test/unit/base/services/authenticationService.test.ts
+++ b/src/test/unit/base/services/authenticationService.test.ts
@@ -3,7 +3,7 @@ import { rejects, strictEqual } from 'assert';
import needle, { NeedleResponse } from 'needle';
import sinon from 'sinon';
import { IBaseSnykModule } from '../../../../snyk/base/modules/interfaces';
-import { AuthenticationService } from '../../../../snyk/base/services/authenticationService';
+import { AuthenticationService, OAuthToken } from '../../../../snyk/base/services/authenticationService';
import { ILoadingBadge } from '../../../../snyk/base/views/loadingBadge';
import { IAnalytics } from '../../../../snyk/common/analytics/itly';
import { IConfiguration } from '../../../../snyk/common/configuration/configuration';
@@ -234,5 +234,40 @@ suite('AuthenticationService', () => {
await rejects(service.updateToken(invalidToken));
sinon.assert.notCalled(setTokenSpy);
});
+
+ test('accepts oauth token', async () => {
+ const oauthToken: OAuthToken = {
+ // eslint-disable-next-line camelcase
+ access_token: 'access_token',
+ expiry: new Date(Date.now() + 10000).toISOString(),
+ // eslint-disable-next-line camelcase
+ refresh_token: 'refresh_token',
+ };
+ const oauthTokenString = JSON.stringify(oauthToken);
+
+ await service.updateToken(oauthTokenString);
+ sinon.assert.calledWith(setTokenSpy, oauthTokenString);
+ });
+
+ test('fails with error on non oauth token json string', async () => {
+ const oauthTokenString = '{}';
+
+ await rejects(service.updateToken(oauthTokenString));
+ sinon.assert.notCalled(setTokenSpy);
+ });
+
+ test('fails with error on setting expired token', async () => {
+ const oauthToken: OAuthToken = {
+ // eslint-disable-next-line camelcase
+ access_token: 'access_token',
+ expiry: new Date(Date.now() - 10000).toISOString(),
+ // eslint-disable-next-line camelcase
+ refresh_token: 'refresh_token',
+ };
+ const oauthTokenString = JSON.stringify(oauthToken);
+
+ await rejects(service.updateToken(oauthTokenString));
+ sinon.assert.notCalled(setTokenSpy);
+ });
});
});
diff --git a/src/test/unit/cli/process.test.ts b/src/test/unit/cli/process.test.ts
index 8d2c8a0c0..ec8104cfb 100644
--- a/src/test/unit/cli/process.test.ts
+++ b/src/test/unit/cli/process.test.ts
@@ -6,9 +6,11 @@ import { Configuration, IConfiguration } from '../../../snyk/common/configuratio
import { ILog } from '../../../snyk/common/logger/interfaces';
import { IVSCodeWorkspace } from '../../../snyk/common/vscode/workspace';
import { LoggerMock } from '../mocks/logger.mock';
+import { OAuthToken } from '../../../snyk/base/services/authenticationService';
suite('CliProcess', () => {
let logger: ILog;
+ const snykOssApiEndpoint = 'https://snykgov.io/api/';
const emptyWorkspace = {
getConfiguration: () => undefined,
} as unknown as IVSCodeWorkspace;
@@ -23,6 +25,7 @@ suite('CliProcess', () => {
{
shouldReportEvents: false,
getToken: () => Promise.resolve(),
+ snykOssApiEndpoint: snykOssApiEndpoint,
} as IConfiguration,
emptyWorkspace,
);
@@ -36,6 +39,7 @@ suite('CliProcess', () => {
{
shouldReportEvents: true,
getToken: () => Promise.resolve(),
+ snykOssApiEndpoint: snykOssApiEndpoint,
} as IConfiguration,
emptyWorkspace,
);
@@ -67,6 +71,28 @@ suite('CliProcess', () => {
strictEqual(envVars['SNYK_CFG_ORG'], organization);
});
+ test('Sets correct token if oauth authentication', async () => {
+ const token = '{"access_token": "fake-token"}';
+ const snykOssApiEndpoint = 'https://snykgov.io/api/';
+ const organization = 'test-org';
+ const process = new CliProcess(
+ logger,
+ {
+ getToken: () => Promise.resolve(token),
+ snykOssApiEndpoint: snykOssApiEndpoint,
+ organization: organization,
+ } as IConfiguration,
+ emptyWorkspace,
+ );
+
+ const envVars = await process.getProcessEnv();
+ const oauthToken = JSON.parse(token) as OAuthToken;
+ strictEqual(envVars['SNYK_TOKEN'], undefined);
+ strictEqual(envVars['SNYK_OAUTH_TOKEN'], oauthToken.access_token);
+ strictEqual(envVars['SNYK_API'], snykOssApiEndpoint);
+ strictEqual(envVars['SNYK_CFG_ORG'], organization);
+ });
+
test('Sets correct proxy variable', async () => {
// arrange
const proxy = 'http://my.proxy.com:8080';
@@ -78,6 +104,7 @@ suite('CliProcess', () => {
{
shouldReportEvents: true,
getToken: () => Promise.resolve(),
+ snykOssApiEndpoint: snykOssApiEndpoint,
} as IConfiguration,
{
getConfiguration: getConfiguration,
diff --git a/src/test/unit/common/experiment/services/experimentService.test.ts b/src/test/unit/common/experiment/services/experimentService.test.ts
index c0ebd393e..c407ca33e 100644
--- a/src/test/unit/common/experiment/services/experimentService.test.ts
+++ b/src/test/unit/common/experiment/services/experimentService.test.ts
@@ -12,7 +12,7 @@ suite('ExperimentService', () => {
let fetchStub: sinon.SinonStub;
setup(() => {
- user = new User(undefined, undefined);
+ user = new User(undefined, undefined, new LoggerMock());
sinon.stub(SnykConfiguration, 'get').resolves({
amplitudeExperimentApiKey: 'test',
diff --git a/src/test/unit/common/languageServer/experiments/codeScanOrchestrator.test.ts b/src/test/unit/common/languageServer/experiments/codeScanOrchestrator.test.ts
index d1a9555fc..e098d583d 100644
--- a/src/test/unit/common/languageServer/experiments/codeScanOrchestrator.test.ts
+++ b/src/test/unit/common/languageServer/experiments/codeScanOrchestrator.test.ts
@@ -29,7 +29,7 @@ suite('Code Scan Orchestrator', () => {
setup(() => {
ls = new LanguageServerMock();
- user = new User(undefined, undefined);
+ user = new User(undefined, undefined, logger);
snykConfig = new SnykConfiguration('test', 'test', 'test');
logger = new LoggerMock();
config = {
diff --git a/src/test/unit/common/languageServer/languageServer.test.ts b/src/test/unit/common/languageServer/languageServer.test.ts
index 171ab9ccd..6a6023e7f 100644
--- a/src/test/unit/common/languageServer/languageServer.test.ts
+++ b/src/test/unit/common/languageServer/languageServer.test.ts
@@ -20,7 +20,7 @@ import { stubWorkspaceConfiguration } from '../../mocks/workspace.mock';
suite('Language Server', () => {
const authServiceMock = {} as IAuthenticationService;
- const user = new User(v4(), undefined);
+ const user = new User(v4(), undefined, new LoggerMock());
let configurationMock: IConfiguration;
let languageServer: LanguageServer;
diff --git a/src/test/unit/common/languageServer/middleware.test.ts b/src/test/unit/common/languageServer/middleware.test.ts
index 3cf334fee..ac52b9a1f 100644
--- a/src/test/unit/common/languageServer/middleware.test.ts
+++ b/src/test/unit/common/languageServer/middleware.test.ts
@@ -58,7 +58,7 @@ suite('Language Server: Middleware', () => {
test('Configuration request should translate settings', async () => {
const middleware = new LanguageClientMiddleware(
configuration,
- new ExperimentService(new User(v4(), undefined), new LoggerMock(), configuration),
+ new ExperimentService(new User(v4(), undefined, new LoggerMock()), new LoggerMock(), configuration),
);
const params: ConfigurationParams = {
items: [
@@ -106,7 +106,7 @@ suite('Language Server: Middleware', () => {
test('Configuration request should return an error', async () => {
const middleware = new LanguageClientMiddleware(
configuration,
- new ExperimentService(new User(v4(), undefined), new LoggerMock(), configuration),
+ new ExperimentService(new User(v4(), undefined, new LoggerMock()), new LoggerMock(), configuration),
);
const params: ConfigurationParams = {
items: [
diff --git a/src/test/unit/common/services/cliConfigService.test.ts b/src/test/unit/common/services/cliConfigService.test.ts
deleted file mode 100644
index bd339c109..000000000
--- a/src/test/unit/common/services/cliConfigService.test.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { strictEqual } from 'assert';
-import sinon from 'sinon';
-import { ISnykApiClient } from '../../../../snyk/common/api/apiСlient';
-import { Configuration, IConfiguration } from '../../../../snyk/common/configuration/configuration';
-import { getSastSettings } from '../../../../snyk/common/services/cliConfigService';
-
-suite('CLI Config Service', () => {
- let config: IConfiguration;
-
- setup(() => {
- config = {
- organization: 'my-super-org',
- } as IConfiguration;
- });
-
- teardown(() => {
- sinon.restore();
- });
-
- test('IDE header and URL query param are passed to settings endpoint', async () => {
- // arrange
- const getFake = sinon.stub().returns({
- data: {},
- });
- const apiClient: ISnykApiClient = {
- get: getFake,
- };
-
- // act
- await getSastSettings(apiClient, config);
-
- // assert
- strictEqual(
- getFake.calledWith(sinon.match.any, {
- headers: {
- 'x-snyk-ide': `${Configuration.source}-${await Configuration.getVersion()}`,
- },
- params: {
- org: config.organization,
- },
- }),
- true,
- );
- });
-});
diff --git a/src/test/unit/common/services/learnService.test.ts b/src/test/unit/common/services/learnService.test.ts
index dc663d1ef..37625331c 100644
--- a/src/test/unit/common/services/learnService.test.ts
+++ b/src/test/unit/common/services/learnService.test.ts
@@ -1,231 +1,90 @@
-import { deepStrictEqual } from 'assert';
-import axios from 'axios';
+import { strictEqual } from 'assert';
import sinon from 'sinon';
-import { OpenCommandIssueType } from '../../../../snyk/common/commands/types';
-import { IConfiguration } from '../../../../snyk/common/configuration/configuration';
-import { CodeIssueData, Issue } from '../../../../snyk/common/languageServer/types';
+import { IVSCodeCommands } from '../../../../snyk/common/vscode/commands';
import { LearnService } from '../../../../snyk/common/services/learnService';
-import type { completeFileSuggestionType } from '../../../../snyk/snykCode/interfaces';
import { OssIssueCommandArg } from '../../../../snyk/snykOss/views/ossVulnerabilityTreeProvider';
-import { LoggerMock } from '../../mocks/logger.mock';
+import { CodeIssueData, Issue, IssueSeverity } from '../../../../snyk/common/languageServer/types';
+import { completeFileSuggestionType } from '../../../../snyk/snykCode/interfaces';
+import { AnalysisSeverity } from '@snyk/code-client';
+import { SNYK_GET_LESSON_COMMAND } from '../../../../snyk/common/constants/commands';
suite('LearnService', () => {
- const ossIssueCommandArgFixture = { identifiers: { CWE: ['CWE-1'] }, packageManager: 'npm' } as OssIssueCommandArg;
- const codeIssueCommandArgFixture = {
- additionalData: {
- isSecurityType: true,
- cwe: ['CWE-2'],
- ruleId: 'javascript%2Fdc_interfile_project%2FSqli',
- },
- } as Issue;
-
- const codeIssueCommandArgFixtureOld = {
- isSecurityType: true,
- cwe: ['CWE-2'],
- id: 'javascript%2Fdc_interfile_project%2FSqli',
- } as completeFileSuggestionType;
-
- const lessonFixture = {
- title: 'lesson title',
- lessonId: 'id',
- ecosystem: 'javascript',
- url: 'https://example.com',
- };
-
- const config = {
- baseApiUrl: 'https://snyk.example.com/',
- } as unknown as IConfiguration;
-
- const loggerMock = new LoggerMock();
- const learnService = new LearnService(config, loggerMock, false);
+ let commands: IVSCodeCommands;
+ const executeCommandFake = sinon.fake();
+ setup(() => {
+ executeCommandFake.resetHistory();
+ commands = {
+ executeCommand: executeCommandFake,
+ } as IVSCodeCommands;
+ });
teardown(() => {
sinon.restore();
});
- suite('OSS specific functionality', () => {
- test('getOSSIssueParams - returns ecosystem & cwes', () => {
- deepStrictEqual(LearnService.getOSSIssueParams(ossIssueCommandArgFixture), {
- rule: ossIssueCommandArgFixture.id,
- ecosystem: ossIssueCommandArgFixture.packageManager,
- cwes: ossIssueCommandArgFixture.identifiers?.CWE,
- cves: ossIssueCommandArgFixture.identifiers?.CVE,
- });
- });
+ test('getOssLesson executes correct command', async () => {
+ const learnService = new LearnService(commands);
- test('getLesson - resolves a lesson', async () => {
- const stub = sinon.stub(axios, 'get').resolves({ data: { lessons: [lessonFixture] } });
- const lesson = await learnService.getLesson(ossIssueCommandArgFixture, OpenCommandIssueType.OssVulnerability);
- deepStrictEqual(lesson?.lessonId, lessonFixture.lessonId);
- deepStrictEqual(stub.getCall(0).args, [
- '/lessons/lookup-for-cta',
- {
- baseURL: `${config.baseApiUrl}/v1/learn`,
- params: {
- source: 'ide',
- rule: ossIssueCommandArgFixture.id,
- ecosystem: ossIssueCommandArgFixture.packageManager,
- cwe: 'CWE-1',
- cve: undefined,
- },
- },
- ]);
- });
+ const issue: OssIssueCommandArg = {
+ id: 'id',
+ packageManager: 'packageManager',
+ } as OssIssueCommandArg;
- test('getLesson - returns null if issue license is truthy', async () => {
- sinon.stub(axios, 'get').resolves({ data: [lessonFixture] });
- const lesson = await learnService.getLesson(
- { ...ossIssueCommandArgFixture, license: 'AGPL' },
- OpenCommandIssueType.OssVulnerability,
- );
- deepStrictEqual(lesson, null);
- });
+ await learnService.getOssLesson(issue);
+ strictEqual(executeCommandFake.calledOnce, true);
+ strictEqual(
+ executeCommandFake.calledWith(SNYK_GET_LESSON_COMMAND, issue.id, issue.packageManager, '', '', 4),
+ true,
+ );
});
-
- suite('CODE specific functionality', () => {
- test('getCodeIssueParams - returns ecosystem & cwes', () => {
- deepStrictEqual(LearnService.getCodeIssueParams(codeIssueCommandArgFixture), {
- ecosystem: 'javascript',
- rule: 'Sqli',
- cwes: ['CWE-2'],
- });
- });
-
- test('getCodeIssueParams - returns ecosystem & cwes - DEPRECATED', () => {
- deepStrictEqual(LearnService.getCodeIssueParamsOld(codeIssueCommandArgFixtureOld), {
- ecosystem: 'javascript',
- rule: 'Sqli',
- cwes: ['CWE-2'],
- });
- });
-
- test('getLesson - resolves a lesson', async () => {
- const stub = sinon.stub(axios, 'get').resolves({ data: { lessons: [lessonFixture] } });
- const lesson = await learnService.getLesson(codeIssueCommandArgFixture, OpenCommandIssueType.CodeIssue);
- deepStrictEqual(lesson?.lessonId, lessonFixture.lessonId);
- deepStrictEqual(stub.getCall(0).args, [
- '/lessons/lookup-for-cta',
- {
- baseURL: `${config.baseApiUrl}/v1/learn`,
- params: {
- source: 'ide',
- cwe: codeIssueCommandArgFixture.additionalData.cwe[0],
- rule: 'Sqli',
- ecosystem: 'javascript',
- cve: undefined,
- },
- },
- ]);
- });
-
- test('getLesson - resolves a lesson - DEPRECATED', async () => {
- const stub = sinon.stub(axios, 'get').resolves({ data: { lessons: [lessonFixture] } });
- const lesson = await learnService.getLesson(codeIssueCommandArgFixtureOld, OpenCommandIssueType.CodeIssueOld);
- deepStrictEqual(lesson?.lessonId, lessonFixture.lessonId);
- deepStrictEqual(stub.getCall(0).args, [
- '/lessons/lookup-for-cta',
- {
- baseURL: `${config.baseApiUrl}/v1/learn`,
- params: {
- source: 'ide',
- cwe: codeIssueCommandArgFixtureOld.cwe[0],
- rule: 'Sqli',
- ecosystem: 'javascript',
- cve: undefined,
- },
- },
- ]);
- });
-
- test('getLesson - returns null if issue isSecurityType is false', async () => {
- sinon.stub(axios, 'get').resolves({ data: { lessons: [lessonFixture] } });
- const lesson = await learnService.getLesson(
- {
- ...codeIssueCommandArgFixture,
- additionalData: { ...codeIssueCommandArgFixture.additionalData, isSecurityType: false },
- },
- OpenCommandIssueType.CodeIssue,
- );
- deepStrictEqual(lesson, null);
- });
-
- test('getLesson - returns null if issue isSecurityType is false', async () => {
- sinon.stub(axios, 'get').resolves({ data: { lessons: [lessonFixture] } });
- const lesson = await learnService.getLesson(
- { ...codeIssueCommandArgFixtureOld, isSecurityType: false },
- OpenCommandIssueType.CodeIssueOld,
- );
- deepStrictEqual(lesson, null);
- });
+ test('getCodeLesson executes correct command', async () => {
+ const learnService = new LearnService(commands);
+ const issue: Issue = {
+ id: 'javascript/nosqli',
+ additionalData: {
+ ruleId: 'javascript/nosqli',
+ cwe: ['CWE-79', 'CWE-89'],
+ message: 'not used',
+ rule: 'not used',
+ repoDatasetSize: 100,
+ exampleCommitFixes: [],
+ text: 'not used',
+ cols: [1, 2],
+ rows: [1, 2],
+ isSecurityType: true,
+ },
+ title: 'not used',
+ severity: IssueSeverity.Critical,
+ filePath: 'not used',
+ };
+
+ await learnService.getCodeLesson(issue);
+ strictEqual(executeCommandFake.calledOnce, true);
+ strictEqual(executeCommandFake.calledWith(SNYK_GET_LESSON_COMMAND, 'nosqli', 'javascript', 'CWE-79', '', 2), true);
});
-
- suite('getLesson', () => {
- test('adds loc=ide query parameter to lesson url', async () => {
- const lessonFixtureWithQueryParams = {
- ...lessonFixture,
- url: 'https://example.com/?test=true',
- };
- sinon.stub(axios, 'get').resolves({ data: { lessons: [lessonFixtureWithQueryParams] } });
- const lesson = await learnService.getLesson(ossIssueCommandArgFixture, OpenCommandIssueType.OssVulnerability);
- deepStrictEqual(lesson?.url, `${lessonFixtureWithQueryParams.url}&loc=ide`);
- });
-
- test('returns null if issueType is not known', async () => {
- const lesson = await learnService.getLesson(
- ossIssueCommandArgFixture,
- 'not known' as unknown as OpenCommandIssueType,
- );
- deepStrictEqual(lesson, null);
- });
-
- test('returns null if the issue has no params', async () => {
- const lessonNoCWE = await learnService.getLesson(
- { ...codeIssueCommandArgFixture, additionalData: { ...codeIssueCommandArgFixture.additionalData, cwe: [] } },
- OpenCommandIssueType.CodeIssue,
- );
- deepStrictEqual(lessonNoCWE, null);
- const lessonNoEcosystem = await learnService.getLesson(
- { ...codeIssueCommandArgFixture, id: '' },
- OpenCommandIssueType.CodeIssue,
- );
- deepStrictEqual(lessonNoEcosystem, null);
- });
-
- test('returns null if the issue has no params - DEPRECATED', async () => {
- const lessonNoCWE = await learnService.getLesson(
- { ...codeIssueCommandArgFixtureOld, cwe: [] },
- OpenCommandIssueType.CodeIssueOld,
- );
- deepStrictEqual(lessonNoCWE, null);
- const lessonNoEcosystem = await learnService.getLesson(
- { ...codeIssueCommandArgFixtureOld, id: '' },
- OpenCommandIssueType.CodeIssueOld,
- );
- deepStrictEqual(lessonNoEcosystem, null);
- });
-
- test('returns null if no lessons are returned', async () => {
- sinon.stub(axios, 'get').resolves({ data: { lessons: [] } });
- const lesson = await learnService.getLesson(ossIssueCommandArgFixture, OpenCommandIssueType.OssVulnerability);
- deepStrictEqual(lesson, null);
- });
-
- test('logs an error and returns null something goes wrong', async () => {
- sinon.stub(axios, 'get').rejects({ message: 'test error' });
- const loggerStub = sinon.stub(loggerMock, 'error').returns(undefined);
-
- const lesson = await learnService.getLesson(ossIssueCommandArgFixture, OpenCommandIssueType.OssVulnerability);
- deepStrictEqual(lesson, null);
- deepStrictEqual(loggerStub.getCall(0).args, ['Error getting Snyk Learn Lesson. {"message":"test error"}']);
- });
-
- test('caches lesson requests', async () => {
- const learnService = new LearnService(config, loggerMock, true);
- const stub = sinon.stub(axios, 'get').resolves({ data: { lessons: [] } });
- await learnService.getLesson(ossIssueCommandArgFixture, OpenCommandIssueType.OssVulnerability);
- deepStrictEqual(stub.calledOnce, true);
- await learnService.getLesson(ossIssueCommandArgFixture, OpenCommandIssueType.OssVulnerability);
- deepStrictEqual(stub.calledOnce, true);
- });
+ test('getCodeLessonOld executes correct command', async () => {
+ const learnService = new LearnService(commands);
+ const issue: completeFileSuggestionType = {
+ categories: [],
+ cols: [0, 0],
+ cwe: ['CWE-79', 'CWE-89'],
+ exampleCommitDescriptions: [],
+ exampleCommitFixes: [],
+ isSecurityType: false,
+ message: '',
+ repoDatasetSize: 0,
+ rows: [0, 0],
+ rule: '',
+ severity: AnalysisSeverity.critical,
+ tags: [],
+ text: '',
+ title: '',
+ uri: '',
+ id: 'javascript/nosqli',
+ };
+
+ await learnService.getCodeLessonOld(issue);
+ strictEqual(executeCommandFake.calledOnce, true);
+ strictEqual(executeCommandFake.calledWith(SNYK_GET_LESSON_COMMAND, 'nosqli', 'javascript', 'CWE-79', '', 2), true);
});
});
diff --git a/src/test/unit/common/user.test.ts b/src/test/unit/common/user.test.ts
index b7e5877ce..6d573531f 100644
--- a/src/test/unit/common/user.test.ts
+++ b/src/test/unit/common/user.test.ts
@@ -1,10 +1,9 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { strictEqual } from 'assert';
-import { AxiosRequestConfig, AxiosResponse } from 'axios';
import sinon from 'sinon';
import { IAnalytics } from '../../../snyk/common/analytics/itly';
-import { ISnykApiClient } from '../../../snyk/common/api/apiСlient';
-import { User } from '../../../snyk/common/user';
+import { User, UserDto } from '../../../snyk/common/user';
+import { IVSCodeCommands } from '../../../snyk/common/vscode/commands';
suite('User', () => {
test('Identification calls analytics identify', async () => {
@@ -12,19 +11,14 @@ suite('User', () => {
const analytics = {
identify: identifyFake,
} as unknown as IAnalytics;
- const apiClient = {
- get(_url: string, _config?: AxiosRequestConfig): Promise> {
- return Promise.resolve({
- data: {
- id: 'test',
- username: 't',
- },
- } as unknown as AxiosResponse);
+ const commandExecutor = {
+ executeCommand(_command, ..._rest) {
+ return Promise.resolve({ id: 'test', username: 't' } as UserDto);
},
- } as ISnykApiClient;
+ } as IVSCodeCommands;
const user = new User();
- await user.identify(apiClient, analytics);
+ await user.identify(commandExecutor, analytics);
strictEqual(identifyFake.called, true);
});
diff --git a/src/test/unit/snykCode/codeSettings.test.ts b/src/test/unit/snykCode/codeSettings.test.ts
index bb917ea54..5c469fa8d 100644
--- a/src/test/unit/snykCode/codeSettings.test.ts
+++ b/src/test/unit/snykCode/codeSettings.test.ts
@@ -1,10 +1,10 @@
import { strictEqual } from 'assert';
import sinon, { SinonSpy } from 'sinon';
-import { ISnykApiClient } from '../../../snyk/common/api/apiСlient';
import { IConfiguration } from '../../../snyk/common/configuration/configuration';
import { SNYK_CONTEXT } from '../../../snyk/common/constants/views';
import { IContextService } from '../../../snyk/common/services/contextService';
import { IOpenerService } from '../../../snyk/common/services/openerService';
+import { IVSCodeCommands } from '../../../snyk/common/vscode/commands';
import { CodeSettings, ICodeSettings } from '../../../snyk/snykCode/codeSettings';
suite('Snyk Code Settings', () => {
@@ -24,7 +24,7 @@ suite('Snyk Code Settings', () => {
viewContext: {},
};
- settings = new CodeSettings({} as ISnykApiClient, contextService, {} as IConfiguration, {} as IOpenerService);
+ settings = new CodeSettings(contextService, {} as IConfiguration, {} as IOpenerService, {} as IVSCodeCommands);
});
teardown(() => {
@@ -75,25 +75,7 @@ suite('Snyk Code Settings', () => {
const codeEnabled = await settings.checkCodeEnabled();
strictEqual(codeEnabled, false);
- strictEqual(setContextFake.calledWith(SNYK_CONTEXT.CODE_ENABLED, true), true);
+ strictEqual(setContextFake.calledWith(SNYK_CONTEXT.CODE_ENABLED, false), true);
strictEqual(setContextFake.calledWith(SNYK_CONTEXT.CODE_LOCAL_ENGINE_ENABLED, true), true);
});
-
- test('Entitlement reportFalsePositivesEnabled gets cached', async () => {
- const getFake = sinon.stub().returns({
- data: {
- reportFalsePositivesEnabled: true,
- },
- });
-
- const apiClient: ISnykApiClient = {
- get: getFake,
- };
-
- settings = new CodeSettings(apiClient, contextService, {} as IConfiguration, {} as IOpenerService);
-
- await settings.getSastSettings();
-
- strictEqual(settings.reportFalsePositivesEnabled, true);
- });
});