diff --git a/CHANGELOG.md b/CHANGELOG.md index e5efe87f5..020aab4ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ - add inline value support for display of vulnerability count - added ai fix feedback support - enable for IntelliJ 2024.3 platform +- require LS protocol version 16 +- transmit project sdks to language server when requested by a scan ### Fixes - add name to code vision provider diff --git a/src/main/kotlin/io/snyk/plugin/services/SnykApplicationSettingsStateService.kt b/src/main/kotlin/io/snyk/plugin/services/SnykApplicationSettingsStateService.kt index 437f07287..98547d86f 100644 --- a/src/main/kotlin/io/snyk/plugin/services/SnykApplicationSettingsStateService.kt +++ b/src/main/kotlin/io/snyk/plugin/services/SnykApplicationSettingsStateService.kt @@ -26,7 +26,7 @@ import java.util.UUID storages = [Storage("snyk.settings.xml", roamingType = RoamingType.DISABLED)], ) class SnykApplicationSettingsStateService : PersistentStateComponent { - val requiredLsProtocolVersion = 15 + val requiredLsProtocolVersion = 16 var useTokenAuthentication = false var currentLSProtocolVersion: Int? = 0 diff --git a/src/main/kotlin/snyk/common/lsp/LanguageServerBulkFileListener.kt b/src/main/kotlin/snyk/common/lsp/LanguageServerBulkFileListener.kt index 7b44d7cf2..f33736a7d 100644 --- a/src/main/kotlin/snyk/common/lsp/LanguageServerBulkFileListener.kt +++ b/src/main/kotlin/snyk/common/lsp/LanguageServerBulkFileListener.kt @@ -15,6 +15,7 @@ import io.snyk.plugin.SnykFile import io.snyk.plugin.getSnykCachedResults import io.snyk.plugin.toLanguageServerURL import io.snyk.plugin.toSnykFileSet +import io.snyk.plugin.ui.toolwindow.SnykPluginDisposable import org.eclipse.lsp4j.DidSaveTextDocumentParams import org.eclipse.lsp4j.TextDocumentIdentifier import org.jetbrains.annotations.TestOnly @@ -122,6 +123,7 @@ class LanguageServerBulkFileListener : SnykBulkFileListener() { VirtualFileManager.getInstance().asyncRefresh() invokeLater { + if (SnykPluginDisposable.getInstance(project).isDisposed() || project.isDisposed) return@invokeLater DaemonCodeAnalyzer.getInstance(project).restart() } } diff --git a/src/main/kotlin/snyk/common/lsp/SnykLanguageClient.kt b/src/main/kotlin/snyk/common/lsp/SnykLanguageClient.kt index 13a456387..d9df12bf8 100644 --- a/src/main/kotlin/snyk/common/lsp/SnykLanguageClient.kt +++ b/src/main/kotlin/snyk/common/lsp/SnykLanguageClient.kt @@ -13,6 +13,7 @@ import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project import com.intellij.openapi.project.ProjectLocator import com.intellij.openapi.project.ProjectManager +import com.intellij.openapi.project.guessProjectForFile import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.io.toNioPathOrNull import com.intellij.openapi.vfs.VfsUtilCore @@ -35,13 +36,16 @@ import org.eclipse.lsp4j.ProgressParams import org.eclipse.lsp4j.PublishDiagnosticsParams import org.eclipse.lsp4j.ShowMessageRequestParams import org.eclipse.lsp4j.WorkDoneProgressCreateParams +import org.eclipse.lsp4j.WorkspaceFolder import org.eclipse.lsp4j.jsonrpc.services.JsonNotification +import org.eclipse.lsp4j.jsonrpc.services.JsonRequest import org.eclipse.lsp4j.services.LanguageClient import org.jetbrains.concurrency.runAsync import snyk.common.ProductType import snyk.common.editor.DocumentChanger import snyk.common.lsp.progress.ProgressManager import snyk.common.lsp.settings.FolderConfigSettings +import snyk.sdk.SdkHelper import snyk.trust.WorkspaceTrustService import java.util.concurrent.ArrayBlockingQueue import java.util.concurrent.CompletableFuture @@ -278,6 +282,13 @@ class SnykLanguageClient : } } + @JsonRequest(value = "workspace/snyk.sdks") + fun getSdks(workspaceFolder: WorkspaceFolder) : CompletableFuture> { + val project = guessProjectForFile(workspaceFolder.uri.toVirtualFile()) ?: return CompletableFuture.completedFuture(emptyList()) + return CompletableFuture.completedFuture(SdkHelper.getSdks(project)) + } + + @JsonNotification(value = "$/snyk.addTrustedFolders") fun addTrustedPaths(param: SnykTrustedFoldersParams) { if (disposed) return diff --git a/src/main/kotlin/snyk/common/lsp/Types.kt b/src/main/kotlin/snyk/common/lsp/Types.kt index cffbf5f38..095d0863f 100644 --- a/src/main/kotlin/snyk/common/lsp/Types.kt +++ b/src/main/kotlin/snyk/common/lsp/Types.kt @@ -18,6 +18,8 @@ import javax.swing.Icon typealias FilterableIssueType = String +data class LsSdk(val type: String, val path: String) + data class CliError( val code: Int? = 0, val error: String? = null, diff --git a/src/main/kotlin/snyk/sdk/SdkHelper.kt b/src/main/kotlin/snyk/sdk/SdkHelper.kt new file mode 100644 index 000000000..cacd2fdcc --- /dev/null +++ b/src/main/kotlin/snyk/sdk/SdkHelper.kt @@ -0,0 +1,31 @@ +package snyk.sdk + +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.Sdk +import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.openapi.util.io.FileUtil +import snyk.common.lsp.LsSdk + +class SdkHelper { + companion object { + fun getSdks(project: Project): List { + val list: MutableList = mutableListOf() + val modules = ModuleManager.getInstance(project).modules + for (module in modules) { + val moduleSdk = ModuleRootManager.getInstance(module).sdk + addSdkToList(moduleSdk, list) + } + return list.toList() + } + + private fun addSdkToList( + sdk: Sdk?, + list: MutableList + ) { + if (sdk != null && sdk.homeDirectory != null) { + list.add(LsSdk(sdk.sdkType.name, FileUtil.toSystemDependentName(sdk.homeDirectory!!.path))) + } + } + } +} diff --git a/src/test/kotlin/io/snyk/plugin/services/download/CliDownloaderServiceIntegTest.kt b/src/test/kotlin/io/snyk/plugin/services/download/CliDownloaderServiceIntegTest.kt index 771b64a4d..118865e57 100644 --- a/src/test/kotlin/io/snyk/plugin/services/download/CliDownloaderServiceIntegTest.kt +++ b/src/test/kotlin/io/snyk/plugin/services/download/CliDownloaderServiceIntegTest.kt @@ -72,7 +72,8 @@ class CliDownloaderServiceIntegTest : LightPlatformTestCase() { /** * Should be THE ONLY test where we actually do download the CLI - * !!! Do __MOCK__ cli download in ANY other test to reduce testing time needed !!! + * 🚨 Do __MOCK__ cli download in ANY other test to reduce testing time needed !!! + * 🚨 This test fails when the preview release is not available yet */ fun testDownloadLatestCliRelease() { ensureCliFileExistent() @@ -131,6 +132,7 @@ class CliDownloaderServiceIntegTest : LightPlatformTestCase() { fun testDownloadLatestCliReleaseShouldHandleHttpStatusException() { val httpStatusException = HttpRequests.HttpStatusException("status bad", HttpStatus.SC_GATEWAY_TIMEOUT, "url") + every { cutSpy.requestLatestReleasesInformation() } returns "1.1294.0" every { downloader.downloadFile(any(), any(), any()) } throws httpStatusException justRun { errorHandler.handleHttpStatusException(httpStatusException, project) }