diff --git a/.eslintrc.js b/.eslintrc.js index 5fcd27b8..a140856d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,20 +1,58 @@ module.exports = { - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], - rules: { - '@typescript-eslint/no-unused-expressions': 'error', - '@typescript-eslint/no-redeclare': 'error', - curly: 'error', - '@typescript-eslint/naming-convention': ['error', { selector: 'class', format: ['PascalCase'] }], - semi: 'error', - eqeqeq: 'error', - quotes: ['error', 'single', { avoidEscape: true }], - 'no-debugger': 'error', - 'no-empty': 'error', - '@typescript-eslint/no-var-requires': 'error', - 'no-unsafe-finally': 'error', - 'new-parens': 'error', - 'no-throw-literal': 'error', - 'no-restricted-imports': ['error', 'require'], + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-require-imports": "error", + '@typescript-eslint/no-unused-expressions': 'error', + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": "default", + "format": ["camelCase"] }, + { + "selector": ["class", "interface", "enum", "enumMember"], + "format": ["PascalCase"] + }, + { + "selector": ["variable", "property", "method"], + "format": ["UPPER_CASE", "camelCase"], + "leadingUnderscore": "allow" + }, + { + "selector": ["typeParameter", "typeAlias"], + "format": ["PascalCase"], + } + ], + "@typescript-eslint/semi": ["error", "always"], + "@typescript-eslint/quotes": [ + "error", + "single", + { + "allowTemplateLiterals": true, + "avoidEscape": true + } + ], + "@typescript-eslint/no-shadow": "error", + "@typescript-eslint/no-redeclare": "error", + "curly": 'error', + "semi": 'off', + "quotes": "off", + "no-shadow": "off", + "no-redeclare": "off", + "no-duplicate-case": "error", + "eqeqeq": ["error", "always"], + 'no-debugger': 'error', + 'no-empty': 'error', + 'no-unsafe-finally': 'error', + 'new-parens': 'error', + 'no-throw-literal': 'error' + }, }; diff --git a/package-lock.json b/package-lock.json index 68d7243f..7accd6a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -478,9 +478,9 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz", - "integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.22.13", diff --git a/src/collector.ts b/src/collector.ts index ed6a03e1..3b8479c7 100644 --- a/src/collector.ts +++ b/src/collector.ts @@ -34,27 +34,27 @@ export interface IPosition { export interface IKeyValueEntry { key: string; value: IVariant; - key_position: IPosition; - value_position: IPosition; + keyPosition: IPosition; + valuePosition: IPosition; context: string; - context_range: Range; + contextRange: Range; } export class KeyValueEntry implements IKeyValueEntry { key: string; value: IVariant; - key_position: IPosition; - value_position: IPosition; + keyPosition: IPosition; + valuePosition: IPosition; context: string; - context_range: Range; + contextRange: Range; - constructor(k: string, pos: IPosition, v?: IVariant, v_pos?: IPosition, c?: string, c_range?: Range) { + constructor(k: string, pos: IPosition, v?: IVariant, vPos?: IPosition, c?: string, cRange?: Range) { this.key = k; - this.key_position = pos; + this.keyPosition = pos; this.value = v; - this.value_position = v_pos; + this.valuePosition = vPos; this.context = c; - this.context_range = c_range; + this.contextRange = cRange; } } @@ -99,16 +99,16 @@ export class Dependency implements IHashableDependency { constructor(dependency: IKeyValueEntry) { this.name = { value: dependency.key, - position: dependency.key_position + position: dependency.keyPosition }; this.version = { value: dependency.value.object, - position: dependency.value_position + position: dependency.valuePosition }; - if (dependency.context && dependency.context_range) { + if (dependency.context && dependency.contextRange) { this.context = { value: dependency.context, - range: dependency.context_range + range: dependency.contextRange }; } } diff --git a/src/config.ts b/src/config.ts index 074f4379..ed3c21fb 100644 --- a/src/config.ts +++ b/src/config.ts @@ -7,41 +7,35 @@ class Config { - exhort_snyk_token: string; - match_manifest_versions: boolean; - provide_fullstack_action: boolean; - forbidden_licenses: Array; - no_crypto: boolean; - home_dir: string; - utm_source: string; - mvn_executable: string; - npm_executable: string; - go_executable: string; - python3_executable: string; - pip3_executable: string; - python_executable: string; - pip_executable: string; - exhort_dev_mode: string; - telemetry_id: string; + exhortSnykToken: string; + matchManifestVersions: boolean; + provideFullstackAction: boolean; + utmSource: string; + mvnExecutable: string; + npmExecutable: string; + goExecutable: string; + python3Executable: string; + pip3Executable: string; + pythonExecutable: string; + pipExecutable: string; + exhortDevMode: string; + telemetryId: string; constructor() { // TODO: this needs to be configurable - this.exhort_snyk_token = process.env.SNYK_TOKEN || ''; - this.match_manifest_versions = (process.env.MATCH_MANIFEST_VERSIONS || '') === 'true'; - this.provide_fullstack_action = (process.env.PROVIDE_FULLSTACK_ACTION || '') === 'true'; - this.forbidden_licenses = []; - this.no_crypto = false; - this.home_dir = process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME']; - this.utm_source = process.env.UTM_SOURCE || ''; - this.mvn_executable = process.env.MVN_EXECUTABLE || 'mvn'; - this.npm_executable = process.env.NPM_EXECUTABLE || 'npm'; - this.go_executable = process.env.GO_EXECUTABLE || 'go'; - this.go_executable = process.env.PYTHON3_EXECUTABLE || 'python3'; - this.go_executable = process.env.PIP3_EXECUTABLE || 'pip3'; - this.go_executable = process.env.PYTHON_EXECUTABLE || 'python'; - this.go_executable = process.env.PIP_EXECUTABLE || 'pip'; - this.exhort_dev_mode = process.env.EXHORT_DEV_MODE || 'false'; - this.telemetry_id = process.env.TELEMETRY_ID || ''; + this.exhortSnykToken = process.env.SNYK_TOKEN || ''; + this.matchManifestVersions = (process.env.MATCH_MANIFEST_VERSIONS || '') === 'true'; + this.provideFullstackAction = (process.env.PROVIDE_FULLSTACK_ACTION || '') === 'true'; + this.utmSource = process.env.UTM_SOURCE || ''; + this.mvnExecutable = process.env.MVN_EXECUTABLE || 'mvn'; + this.npmExecutable = process.env.NPM_EXECUTABLE || 'npm'; + this.goExecutable = process.env.GO_EXECUTABLE || 'go'; + this.python3Executable = process.env.PYTHON3_EXECUTABLE || 'python3'; + this.pip3Executable = process.env.PIP3_EXECUTABLE || 'pip3'; + this.pythonExecutable = process.env.PYTHON_EXECUTABLE || 'python'; + this.pipExecutable = process.env.PIP_EXECUTABLE || 'pip'; + this.exhortDevMode = process.env.EXHORT_DEV_MODE || 'false'; + this.telemetryId = process.env.TELEMETRY_ID || ''; } } diff --git a/src/consumers.ts b/src/consumers.ts index c161f72d..dbf48c82 100644 --- a/src/consumers.ts +++ b/src/consumers.ts @@ -4,7 +4,7 @@ * ------------------------------------------------------------------------------------------ */ 'use strict'; import { IDependency } from './collector'; -import { get_range } from './utils'; +import { getRange } from './utils'; import { Vulnerability } from './vulnerability'; import { VulnerabilityAggregator } from './aggregators'; import { Diagnostic, CodeAction } from 'vscode-languageserver'; @@ -15,9 +15,9 @@ interface IBindingDescriptor { } /* Bind & return the part of `obj` as described by `desc` */ -let bind_object = (obj: any, desc: IBindingDescriptor) => { +const bindObject = (obj: any, desc: IBindingDescriptor) => { let bind = obj; - for (let elem of desc.path) { + for (const elem of desc.path) { if (elem in bind) { bind = bind[elem]; } else { @@ -30,7 +30,7 @@ let bind_object = (obj: any, desc: IBindingDescriptor) => { /* Arbitrary metadata consumer interface */ interface IConsumer { refbinding: IBindingDescriptor; - ref: any; + ref: string; consume(data: any): boolean; } @@ -72,7 +72,7 @@ class DiagnosticsPipeline implements IPipeline run(data: any): Vulnerability { if (this.item.consume(data)) { - let vulnerability = this.item.produce(); + const vulnerability = this.item.produce(); const aggVulnerability = this.vulnerabilityAggregator.aggregate(vulnerability); if (this.vulnerabilityAggregator.isNewVulnerability) { const aggDiagnostic = aggVulnerability.getDiagnostic(); @@ -145,29 +145,29 @@ class AnalysisConsumer implements IConsumer { constructor(public config: any) { } consume(data: any): boolean { if (this.refbinding !== null) { - this.ref = bind_object(data, this.refbinding); + this.ref = bindObject(data, this.refbinding); } if (this.issuesBinding !== null) { - this.issues = bind_object(data, this.issuesBinding); + this.issues = bindObject(data, this.issuesBinding); this.issuesCount = this.issues !== null ? this.issues.length : 0; } // if (this.recommendationBinding !== null) { - // this.recommendation = bind_object(data, this.recommendationBinding); + // this.recommendation = bindObject(data, this.recommendationBinding); // } // if (this.recommendation !== null && this.recommendationNameBinding !== null) { - // this.recommendationName = bind_object(data, this.recommendationNameBinding); + // this.recommendationName = bindObject(data, this.recommendationNameBinding); // } // if (this.recommendation !== null && this.recommendationVersionBinding !== null) { - // this.recommendationVersion = bind_object(data, this.recommendationVersionBinding); + // this.recommendationVersion = bindObject(data, this.recommendationVersionBinding); // } // if (this.remediationsBinding !== null) { - // this.remediations = bind_object(data, this.remediationsBinding); + // this.remediations = bindObject(data, this.remediationsBinding); // } if (this.highestVulnerabilityBinding !== null) { - this.highestVulnerability = bind_object(data, this.highestVulnerabilityBinding); + this.highestVulnerability = bindObject(data, this.highestVulnerabilityBinding); } if (this.highestVulnerability !== null && this.highestVulnerabilitySeverityBinding !== null) { - this.highestVulnerabilitySeverity = bind_object(data, this.highestVulnerabilitySeverityBinding); + this.highestVulnerabilitySeverity = bindObject(data, this.highestVulnerabilitySeverityBinding); } return this.ref !== null; } @@ -189,7 +189,7 @@ class SecurityEngine extends AnalysisConsumer implements DiagnosticProducer { produce(): Vulnerability { return new Vulnerability( - get_range(this.context), + getRange(this.context), this.ref, this.issuesCount, // this.recommendation, @@ -202,6 +202,6 @@ class SecurityEngine extends AnalysisConsumer implements DiagnosticProducer { } } -let codeActionsMap = new Map(); +const codeActionsMap = new Map(); export { DiagnosticsPipeline, SecurityEngine, codeActionsMap }; \ No newline at end of file diff --git a/src/providers/go.mod.ts b/src/providers/go.mod.ts index 7ddaa1ec..973e740b 100644 --- a/src/providers/go.mod.ts +++ b/src/providers/go.mod.ts @@ -31,7 +31,7 @@ class NaiveGomodParser { const replaceWithIndex = line.lastIndexOf(parts[1]); const replaceEntry: IKeyValueEntry = new KeyValueEntry(replaceWith[0].trim(), { line: 0, column: 0 }); replaceEntry.value = new Variant(ValueType.String, 'v' + replaceWithVersion[0]); - replaceEntry.value_position = { line: index + 1, column: (replaceWithIndex + replaceWithVersion.index) }; + replaceEntry.valuePosition = { line: index + 1, column: (replaceWithIndex + replaceWithVersion.index) }; const replaceDependency = new Dependency(replaceEntry); const isReplaceToVersion: boolean = replaceToVersion && replaceToVersion.length > 0; return {key: replaceTo[0].trim() + (isReplaceToVersion ? ('@v' + replaceToVersion[0]) : ''), value: replaceDependency}; @@ -51,7 +51,7 @@ class NaiveGomodParser { } static parseDependencies(contents:string): Array { - let replaceMap = new Map(); + const replaceMap = new Map(); let isExcluded = false; let goModDeps = contents.split('\n').reduce((dependencies, line, index) => { // ignore excluded dependencies @@ -75,7 +75,7 @@ class NaiveGomodParser { // stash replacement dependencies for replacement if (line.includes('=>')) { - let replaceEntry = NaiveGomodParser.getReplaceMap(line, index); + const replaceEntry = NaiveGomodParser.getReplaceMap(line, index); if (replaceEntry) { replaceMap.set(replaceEntry.key, replaceEntry.value); } @@ -90,7 +90,7 @@ class NaiveGomodParser { if (pkgName.length > 0) { const entry: IKeyValueEntry = new KeyValueEntry(pkgName, { line: 0, column: 0 }); entry.value = new Variant(ValueType.String, 'v' + version[0]); - entry.value_position = { line: index + 1, column: version.index }; + entry.valuePosition = { line: index + 1, column: version.index }; // Push all direct and indirect modules present in go.mod (manifest) dependencies.push(new Dependency(entry)); } @@ -118,7 +118,7 @@ export class DependencyProvider implements IDependencyProvider { } async collect(contents: string): Promise> { - let parser = new NaiveGomodParser(contents); + const parser = new NaiveGomodParser(contents); return parser.parse(); } } diff --git a/src/providers/package.json.ts b/src/providers/package.json.ts index 7538f7b2..69c6ca8e 100644 --- a/src/providers/package.json.ts +++ b/src/providers/package.json.ts @@ -24,9 +24,9 @@ export class DependencyProvider implements IDependencyProvider { filter(c => this.classes.includes(c.key.value)). flatMap(c => c.value.children). map(c => { - let entry: IKeyValueEntry = new KeyValueEntry(c.key.value, {line: c.key.loc.start.line, column: c.key.loc.start.column + 1}); + const entry: IKeyValueEntry = new KeyValueEntry(c.key.value, {line: c.key.loc.start.line, column: c.key.loc.start.column + 1}); entry.value = new Variant(ValueType.String, c.value.value); - entry.value_position = {line: c.value.loc.start.line, column: c.value.loc.start.column + 1}; + entry.valuePosition = {line: c.value.loc.start.line, column: c.value.loc.start.column + 1}; return new Dependency(entry); }); } diff --git a/src/providers/pom.xml.ts b/src/providers/pom.xml.ts index aa89dcc4..15c58832 100644 --- a/src/providers/pom.xml.ts +++ b/src/providers/pom.xml.ts @@ -49,14 +49,14 @@ export class DependencyProvider implements IDependencyProvider { return [this.groupId, this.artifactId].find(e => !e.textContents[0]?.text) === undefined; } - }; + } const toDependency = (d: PomDependency): Dependency => { const dep: IKeyValueEntry = new KeyValueEntry( `${d.groupId.textContents[0].text}/${d.artifactId.textContents[0].text}`, { line: d.element.position.startLine, column: d.element.position.startColumn } ); - dep.context_range = { + dep.contextRange = { start: { line: d.element.position.startLine - 1, character: d.element.position.startColumn - 1 }, end: { line: d.element.position.endLine - 1, character: d.element.position.endColumn } }; @@ -64,10 +64,10 @@ export class DependencyProvider implements IDependencyProvider { if (d.version && d.version.textContents.length > 0) { dep.value = new Variant(ValueType.String, d.version.textContents[0].text); const versionVal = d.version.textContents[0]; - dep.value_position = { line: versionVal.position.startLine, column: versionVal.position.startColumn }; + dep.valuePosition = { line: versionVal.position.startLine, column: versionVal.position.startColumn }; } else { dep.value = new Variant(ValueType.String, ''); - dep.value_position = { line: 0, column: 0 }; + dep.valuePosition = { line: 0, column: 0 }; dep.context = dependencyTemplate(d.element); } return new Dependency(dep); @@ -76,7 +76,7 @@ export class DependencyProvider implements IDependencyProvider { const dependencyTemplate = (dep: XMLElement): string => { let template = ''; let idx = 0; - let margin = dep.textContents[idx].text; + const margin = dep.textContents[idx].text; dep.subElements.forEach(e => { if (e.name !== 'version') { template += `${dep.textContents[idx++].text}<${e.name}>${e.textContents[0].text}`; @@ -89,12 +89,12 @@ export class DependencyProvider implements IDependencyProvider { const purgeTestDeps = (nodes: XMLElement[]): Array => nodes // no test dependencies - .filter(e => !e.subElements.find(e => (e.name === 'scope' && e.textContents[0]?.text === 'test'))) + .filter(e => !e.subElements.find(elm => (elm.name === 'scope' && elm.textContents[0]?.text === 'test'))) .map(e => new PomDependency(e)); const validDeps = purgeTestDeps(deps).filter(e => e.isValid()); - const result = new Array(); + const result = []; validDeps.forEach((d) => { result.push(toDependency(d)); }); @@ -108,7 +108,7 @@ export class DependencyProvider implements IDependencyProvider { } private getXMLDependencies(doc: XMLDocument): Array { - let validElementNames = ['groupId', 'artifactId']; + const validElementNames = ['groupId', 'artifactId']; return this.findRootNodes(doc, 'dependencies') //must not be a dependency under dependencyManagement @@ -120,6 +120,6 @@ export class DependencyProvider implements IDependencyProvider { .flat(1) .filter(e => e.name === 'dependency') // must include all validElementNames - .filter(e => e.subElements.filter(e => validElementNames.includes(e.name)).length === validElementNames.length); + .filter(e => e.subElements.filter(elm => validElementNames.includes(elm.name)).length === validElementNames.length); } } diff --git a/src/providers/requirements.txt.ts b/src/providers/requirements.txt.ts index 6485ee45..f659af5c 100644 --- a/src/providers/requirements.txt.ts +++ b/src/providers/requirements.txt.ts @@ -23,7 +23,7 @@ class NaivePyParser { const version = (parsedRequirement[1] || '').trim(); const entry: IKeyValueEntry = new KeyValueEntry(pkgName, { line: 0, column: 0 }); entry.value = new Variant(ValueType.String, version); - entry.value_position = { line: index + 1, column: req.indexOf(version) + 1 }; + entry.valuePosition = { line: index + 1, column: req.indexOf(version) + 1 }; dependencies.push(new Dependency(entry)); } return dependencies; @@ -44,7 +44,7 @@ export class DependencyProvider implements IDependencyProvider { } async collect(contents: string): Promise> { - let parser = new NaivePyParser(contents); + const parser = new NaivePyParser(contents); return parser.parse(); } } diff --git a/src/server.ts b/src/server.ts index 5b5f39fd..bbb2eb24 100644 --- a/src/server.ts +++ b/src/server.ts @@ -8,8 +8,7 @@ import * as path from 'path'; import { createConnection, - TextDocuments, InitializeResult, - CodeLens, CodeAction, CodeActionKind, + TextDocuments, InitializeResult, CodeAction, CodeActionKind, ProposedFeatures } from 'vscode-languageserver/node'; @@ -20,7 +19,7 @@ import { DependencyProvider as RequirementsTxt } from './providers/requirements. import { DependencyMap, IDependencyProvider } from './collector'; import { SecurityEngine, DiagnosticsPipeline, codeActionsMap } from './consumers'; import { NoopVulnerabilityAggregator, MavenVulnerabilityAggregator } from './aggregators'; -import { AnalyticsSource } from './vulnerability'; +import { ANALYTICS_SOURCE } from './vulnerability'; import { config } from './config'; import { TextDocumentSyncKind, Connection, DidChangeConfigurationNotification } from 'vscode-languageserver'; import { TextDocument } from 'vscode-languageserver-textdocument'; @@ -30,8 +29,7 @@ import exhort from '@RHEcosystemAppEng/exhort-javascript-api'; enum EventStream { Invalid, - Diagnostics, - CodeLens + Diagnostics } // Create a connection for the server, using Node's IPC as a transport. @@ -45,7 +43,7 @@ let triggerFullStackAnalysis: string; let triggerRHRepositoryRecommendationNotification: string; let hasConfigurationCapability: boolean = false; connection.onInitialize((params): InitializeResult => { - let capabilities = params.capabilities; + const capabilities = params.capabilities; triggerFullStackAnalysis = params.initializationOptions.triggerFullStackAnalysis; triggerRHRepositoryRecommendationNotification = params.initializationOptions.triggerRHRepositoryRecommendationNotification; hasConfigurationCapability = !!( @@ -74,15 +72,15 @@ interface RedhatDependencyAnalyticsSettings { // Initializing default settings for Red Hat Dependency Analytics const defaultSettings: RedhatDependencyAnalyticsSettings = { - exhortSnykToken: config.exhort_snyk_token, - matchManifestVersions: config.match_manifest_versions, - mvnExecutable: config.mvn_executable, - npmExecutable: config.npm_executable, - goExecutable: config.go_executable, - python3Executable: config.python3_executable, - pip3Executable: config.pip3_executable, - pythonExecutable: config.python_executable, - pipExecutable: config.pip_executable + exhortSnykToken: config.exhortSnykToken, + matchManifestVersions: config.matchManifestVersions, + mvnExecutable: config.mvnExecutable, + npmExecutable: config.npmExecutable, + goExecutable: config.goExecutable, + python3Executable: config.python3Executable, + pip3Executable: config.pip3Executable, + pythonExecutable: config.pythonExecutable, + pipExecutable: config.pipExecutable }; // Creating a mutable variable to hold the global settings for Red Hat Dependency Analytics. @@ -100,7 +98,7 @@ interface IAnalysisFileHandler { interface IAnalysisFiles { handlers: Array; - file_data: Map; + fileData: Map; on(stream: EventStream, matcher: string, cb: IFileHandlerCallback): IAnalysisFiles; run(stream: EventStream, uri: string, file: string, contents: string): any; } @@ -114,17 +112,17 @@ class AnalysisFileHandler implements IAnalysisFileHandler { class AnalysisFiles implements IAnalysisFiles { handlers: Array; - file_data: Map; + fileData: Map; constructor() { this.handlers = []; - this.file_data = new Map(); + this.fileData = new Map(); } on(stream: EventStream, matcher: string, cb: IFileHandlerCallback): IAnalysisFiles { this.handlers.push(new AnalysisFileHandler(matcher, stream, cb)); return this; } run(stream: EventStream, uri: string, file: string, contents: string): any { - for (let handler of this.handlers) { + for (const handler of this.handlers) { if (handler.stream === stream && handler.matcher.test(file)) { return handler.callback(uri, file, contents); } @@ -133,35 +131,27 @@ class AnalysisFiles implements IAnalysisFiles { } interface IAnalysisLSPServer { - connection: Connection; + conn: Connection; files: IAnalysisFiles; - handle_file_event(uri: string, contents: string): void; - handle_code_lens_event(uri: string): CodeLens[]; + handleFileEvent(uri: string, contents: string): void; } class AnalysisLSPServer implements IAnalysisLSPServer { - constructor(public connection: Connection, public files: IAnalysisFiles) { } + constructor(public conn: Connection, public files: IAnalysisFiles) { } - handle_file_event(uri: string, contents: string): void { - let path_name = new URL(uri).pathname; - let file_name = path.basename(path_name); + handleFileEvent(uri: string, contents: string): void { + const pathName = new URL(uri).pathname; + const fileName = path.basename(pathName); - this.files.file_data[uri] = contents; + this.files.fileData[uri] = contents; - this.files.run(EventStream.Diagnostics, uri, file_name, contents); - } - - handle_code_lens_event(uri: string): CodeLens[] { - let path_name = new URL(uri).pathname; - let file_name = path.basename(path_name); - let contents = this.files.file_data[uri]; - return this.files.run(EventStream.CodeLens, uri, file_name, contents); + this.files.run(EventStream.Diagnostics, uri, fileName, contents); } } -let files: IAnalysisFiles = new AnalysisFiles(); -let server: IAnalysisLSPServer = new AnalysisLSPServer(connection, files); +const files: IAnalysisFiles = new AnalysisFiles(); +const server: IAnalysisLSPServer = new AnalysisLSPServer(connection, files); // total counts of known security vulnerabilities class VulnCount { @@ -186,10 +176,10 @@ const getCAmsg = (deps, diagnostics, vulnCount): string => { function runPipeline(dependencies, diagnostics, packageAggregator, diagnosticFilePath, pkgMap: DependencyMap, vulnCount, provider: IDependencyProvider) { dependencies.forEach(d => { // match dependency with dependency from package map - let pkg = pkgMap.get(d.ref.split('@')[0].replace(`pkg:${provider.ecosystem}/`, '')); + const pkg = pkgMap.get(d.ref.split('@')[0].replace(`pkg:${provider.ecosystem}/`, '')); // if dependency mached, run diagnostic if (pkg !== undefined) { - let pipeline = new DiagnosticsPipeline(SecurityEngine, pkg, config, diagnostics, packageAggregator, diagnosticFilePath); + const pipeline = new DiagnosticsPipeline(SecurityEngine, pkg, config, diagnostics, packageAggregator, diagnosticFilePath); pipeline.run(d); const secEng = pipeline.item as SecurityEngine; vulnCount.issuesCount += secEng.issuesCount; @@ -200,7 +190,7 @@ function runPipeline(dependencies, diagnostics, packageAggregator, diagnosticFil } // Fetch Vulnerabilities by component analysis API call -const fetchVulnerabilities = async (fileType: string, reqData: any) => { +const fetchVulnerabilities = async (fileType: string, reqData: string) => { // set up configuration options for the component analysis request const options = { @@ -211,9 +201,9 @@ const fetchVulnerabilities = async (fileType: string, reqData: any) => { 'EXHORT_PIP3_PATH': globalSettings.pip3Executable, 'EXHORT_PYTHON_PATH': globalSettings.pythonExecutable, 'EXHORT_PIP_PATH': globalSettings.pipExecutable, - 'EXHORT_DEV_MODE': config.exhort_dev_mode, - 'RHDA_TOKEN': config.telemetry_id, - 'RHDA_SOURCE': config.utm_source, + 'EXHORT_DEV_MODE': config.exhortDevMode, + 'RHDA_TOKEN': config.telemetryId, + 'RHDA_SOURCE': config.utmSource, 'MATCH_MANIFEST_VERSIONS': globalSettings.matchManifestVersions }; if (globalSettings.exhortSnykToken !== '') { @@ -223,10 +213,10 @@ const fetchVulnerabilities = async (fileType: string, reqData: any) => { try { // get component analysis in JSON format - let componentAnalysisJson = await exhort.componentAnalysis(fileType, reqData, options); + const componentAnalysisJson = await exhort.componentAnalysis(fileType, reqData, options); // check vulnerability provider statuses - let ko = new Array(); + const ko = []; componentAnalysisJson.summary.providerStatuses.forEach(ps => { if (!ps.ok) { ko.push(ps.provider); @@ -287,7 +277,7 @@ const sendDiagnostics = async (diagnosticFilePath: string, contents: string, pro const pkgMap = new DependencyMap(deps); // init aggregator - let packageAggregator = provider.ecosystem === 'maven' ? new MavenVulnerabilityAggregator(provider) : new NoopVulnerabilityAggregator(provider); + const packageAggregator = provider.ecosystem === 'maven' ? new MavenVulnerabilityAggregator(provider) : new NoopVulnerabilityAggregator(provider); // init tracking components const diagnostics = []; @@ -331,27 +321,27 @@ let checkDelay; // triggered when document is opened connection.onDidOpenTextDocument((params) => { - server.handle_file_event(params.textDocument.uri, params.textDocument.text); + server.handleFileEvent(params.textDocument.uri, params.textDocument.text); }); // triggered when document is saved connection.onDidSaveTextDocument((params) => { clearTimeout(checkDelay); - server.handle_file_event(params.textDocument.uri, server.files.file_data[params.textDocument.uri]); + server.handleFileEvent(params.textDocument.uri, server.files.fileData[params.textDocument.uri]); }); // triggered when changes have been applied to document connection.onDidChangeTextDocument((params) => { /* Update internal state for code lenses */ - server.files.file_data[params.textDocument.uri] = params.contentChanges[0].text; + server.files.fileData[params.textDocument.uri] = params.contentChanges[0].text; clearTimeout(checkDelay); checkDelay = setTimeout(() => { - server.handle_file_event(params.textDocument.uri, server.files.file_data[params.textDocument.uri]); + server.handleFileEvent(params.textDocument.uri, server.files.fileData[params.textDocument.uri]); }, 3000); }); // triggered when document is closed -connection.onDidCloseTextDocument((params) => { +connection.onDidCloseTextDocument(() => { clearTimeout(checkDelay); }); @@ -367,7 +357,7 @@ connection.onInitialized(() => { connection.onDidChangeConfiguration(() => { if (hasConfigurationCapability) { // Fetching the workspace configuration from the client. - server.connection.workspace.getConfiguration().then((data) => { + server.conn.workspace.getConfiguration().then((data) => { // Updating global settings based on the fetched configuration data. globalSettings = ({ exhortSnykToken: data.redHatDependencyAnalytics.exhortSnykToken, @@ -395,10 +385,10 @@ const fullStackReportAction = (): CodeAction => ({ connection.onCodeAction((params): CodeAction[] => { - let codeActions: CodeAction[] = []; + const codeActions: CodeAction[] = []; let hasAnalyticsDiagonostic: boolean = false; - for (let diagnostic of params.context.diagnostics) { - let codeAction = codeActionsMap[diagnostic.range.start.line + '|' + diagnostic.range.start.character]; + for (const diagnostic of params.context.diagnostics) { + const codeAction = codeActionsMap[diagnostic.range.start.line + '|' + diagnostic.range.start.character]; if (codeAction) { if (path.basename(params.textDocument.uri) === 'pom.xml') { @@ -412,10 +402,10 @@ connection.onCodeAction((params): CodeAction[] => { } if (!hasAnalyticsDiagonostic) { - hasAnalyticsDiagonostic = diagnostic.source === AnalyticsSource; + hasAnalyticsDiagonostic = diagnostic.source === ANALYTICS_SOURCE; } } - if (config.provide_fullstack_action && hasAnalyticsDiagonostic) { + if (config.provideFullstackAction && hasAnalyticsDiagonostic) { codeActions.push(fullStackReportAction()); } return codeActions; diff --git a/src/utils.ts b/src/utils.ts index 35db0cbe..46bb25ba 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,32 +5,31 @@ 'use strict'; import { Position, Range } from 'vscode-languageserver'; import { IPositionedString, IPosition, IDependency } from './collector'; -import { config } from './config'; /* VSCode and Che transmit the file buffer in a different manner, * so we have to use different functions for computing the * positions and ranges so that the lines are rendered properly. */ -let _to_lsp_position_che = (pos: IPosition): Position => { +const _toLspPositionChe = (pos: IPosition): Position => { return {line: pos.line - 1, character: pos.column - 1}; }; -let _get_range_che = (ps: IPositionedString): Range => { - let length = ps.value.length; +const _getRangeChe = (ps: IPositionedString): Range => { + const length = ps.value.length; return { - start: to_lsp_position(ps.position), + start: _toLspPosition(ps.position), end: {line: ps.position.line - 1, character: ps.position.column + length - 1} }; }; -export let to_lsp_position = (pos: IPosition): Position => { - return _to_lsp_position_che(pos); +export const _toLspPosition = (pos: IPosition): Position => { + return _toLspPositionChe(pos); }; -export let get_range = (dep: IDependency): Range => { +export const getRange = (dep: IDependency): Range => { if (dep.version.position.line !== 0) { - return _get_range_che(dep.version); + return _getRangeChe(dep.version); } else { return dep.context.range; } diff --git a/src/vulnerability.ts b/src/vulnerability.ts index 6b82e2a7..e5e8c062 100644 --- a/src/vulnerability.ts +++ b/src/vulnerability.ts @@ -8,7 +8,7 @@ import { Range } from 'vscode-languageserver'; import { VERSION_TEMPLATE } from './utils'; import { IDependencyProvider } from './collector'; -const AnalyticsSource = '\nRed Hat Dependency Analytics Plugin [Powered by Snyk]'; +const ANALYTICS_SOURCE = '\nRed Hat Dependency Analytics Plugin [Powered by Snyk]'; /* Vulnerability data along with package name and version */ class Vulnerability { @@ -60,8 +60,8 @@ class Vulnerability { // } } - let diagSeverity = DiagnosticSeverity.Error; - let msg = `${this.ref.replace(`pkg:${this.provider.ecosystem}/`, '')} + const diagSeverity = DiagnosticSeverity.Error; + const msg = `${this.ref.replace(`pkg:${this.provider.ecosystem}/`, '')} Known security vulnerabilities: ${this.issuesCount} Highest severity: ${this.highestVulnerabilitySeverity}`; // msg = `${this.ref} @@ -73,9 +73,9 @@ Highest severity: ${this.highestVulnerabilitySeverity}`; severity: diagSeverity, range: this.range, message: msg, - source: AnalyticsSource, + source: ANALYTICS_SOURCE, }; } } -export { Vulnerability, AnalyticsSource }; \ No newline at end of file +export { Vulnerability, ANALYTICS_SOURCE }; \ No newline at end of file diff --git a/test/aggregators.test.ts b/test/aggregators.test.ts index 04f64b74..466deb55 100644 --- a/test/aggregators.test.ts +++ b/test/aggregators.test.ts @@ -3,7 +3,7 @@ import { Range } from 'vscode-languageserver'; import { DependencyProvider as PackageJson } from '../src/providers/package.json'; import { DependencyProvider as PomXml } from '../src/providers/pom.xml'; import { NoopVulnerabilityAggregator, MavenVulnerabilityAggregator } from '../src/aggregators'; -import { Vulnerability } from '../src/vulnerability'; +import { Vulnerability, ANALYTICS_SOURCE } from '../src/vulnerability'; const dummyRange: Range = { start: { @@ -16,8 +16,6 @@ const dummyRange: Range = { } } -const AnalyticsSource = '\nRed Hat Dependency Analytics Plugin [Powered by Snyk]';; - describe('Noop vulnerability aggregator tests', () => { it('Test Noop aggregator', async () => { @@ -31,7 +29,7 @@ describe('Noop vulnerability aggregator tests', () => { // severity: DiagnosticSeverity.Information, // range: dummyRange, // message: msg, - // source: AnalyticsSource, + // source: ANALYTICS_SOURCE, // }; expect(noopVulnerabilityAggregator.isNewVulnerability).to.equal(true); @@ -53,7 +51,7 @@ describe('Maven vulnerability aggregator tests', () => { // severity: DiagnosticSeverity.Information, // range: dummyRange, // message: msg, - // source: AnalyticsSource, + // source: ANALYTICS_SOURCE, // }; expect(mavenVulnerabilityAggregator.isNewVulnerability).to.equal(true); diff --git a/test/vulnerability.test.ts b/test/vulnerability.test.ts index e0016e24..1e0581b6 100644 --- a/test/vulnerability.test.ts +++ b/test/vulnerability.test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { Diagnostic, DiagnosticSeverity, Range } from 'vscode-languageserver'; import { DependencyProvider as PomXml } from '../src/providers/pom.xml'; -import { Vulnerability } from '../src/vulnerability'; +import { Vulnerability, ANALYTICS_SOURCE } from '../src/vulnerability'; describe('Vulnerability tests', () => { const dummyRange: Range = { @@ -15,8 +15,6 @@ describe('Vulnerability tests', () => { } }; - const AnalyticsSource = '\nRed Hat Dependency Analytics Plugin [Powered by Snyk]'; - // it('Test vulnerability with minimal fields/without vulnerabilities and without recommendations', async () => { // let vulnerability = new Vulnerability( // dummyRange @@ -27,7 +25,7 @@ describe('Vulnerability tests', () => { // severity: DiagnosticSeverity.Information, // range: dummyRange, // message: msg, - // source: AnalyticsSource, + // source: ANALYTICS_SOURCE, // }; // expect(vulnerability.getDiagnostic().toString().replace(/\s/g, "")).is.eql(expectedDiagnostic.toString().replace(/\s/g, "")); @@ -50,7 +48,7 @@ describe('Vulnerability tests', () => { // severity: DiagnosticSeverity.Information, // range: dummyRange, // message: msg, - // source: AnalyticsSource, + // source: ANALYTICS_SOURCE, // }; // expect(vulnerability.getDiagnostic().toString().replace(/\s/g, "")).is.eql(expectedDiagnostic.toString().replace(/\s/g, "")); @@ -73,7 +71,7 @@ describe('Vulnerability tests', () => { // severity: DiagnosticSeverity.Error, // range: dummyRange, // message: msg, - // source: AnalyticsSource, + // source: ANALYTICS_SOURCE, // }; // expect(vulnerability.getDiagnostic().toString().replace(/\s/g, "")).is.eql(expectedDiagnostic.toString().replace(/\s/g, "")); @@ -96,7 +94,7 @@ describe('Vulnerability tests', () => { // severity: DiagnosticSeverity.Error, // range: dummyRange, // message: msg, - // source: AnalyticsSource, + // source: ANALYTICS_SOURCE, // }; // expect(vulnerability.getDiagnostic().toString().replace(/\s/g, "")).is.eql(expectedDiagnostic.toString().replace(/\s/g, "")); @@ -125,7 +123,7 @@ describe('Vulnerability tests', () => { severity: DiagnosticSeverity.Error, range: dummyRange, message: msg, - source: AnalyticsSource, + source: ANALYTICS_SOURCE, }; expect(vulnerability.getDiagnostic().toString().replace(/\s/g, "")).is.eql(expectedDiagnostic.toString().replace(/\s/g, ""));