Skip to content

Commit

Permalink
fix: support for 2023.3 by implementing threading and UI changes [HEA…
Browse files Browse the repository at this point in the history
…D-1174] (#463)

* fix: wrap customizeCellRenderer logic in readAction

* fix: UI deprecations & oss performance

next step code, iac, advisor

* fix: long operations error in UI thread and some refactorings

* fix: iac & code separation of navigation logic and ui logic

* fix: product selection preference panel

* fix: separate container navigation logic from UI, fix some more deprecations

* fix: tests

* fix: test tear down in SnykToolWindowPanelIntegTest.kt

* fix: test tear down in OssBulkFileListenerTest

* fix: additional tests

* fix: download tests & taskqueue

* fix: tests and erroneous mocking

* fix: environment for language server

extracted the CLI environment logic to a third helper file to be used also by language server.

---------

Co-authored-by: Bastian Doetsch <[email protected]>
  • Loading branch information
PeterSchafer and bastiandoetsch authored Jan 11, 2024
1 parent 2594516 commit 8704272
Show file tree
Hide file tree
Showing 49 changed files with 497 additions and 487 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fun properties(key: String) = project.findProperty(key).toString()

plugins {
id("org.jetbrains.changelog") version "2.1.2"
id("org.jetbrains.intellij") version "1.16.0"
id("org.jetbrains.intellij") version "1.16.1"
id("org.jetbrains.kotlin.jvm") version "1.9.0"
id("io.gitlab.arturbosch.detekt") version ("1.23.1")
id("pl.allegro.tech.build.axion-release") version "1.13.6"
Expand Down
8 changes: 4 additions & 4 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ pluginName=Snyk Security - Code, Open Source, Container, IaC Configurations

# for insight into build numbers and IntelliJ Platform versions
# see https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
pluginSinceBuild=231
pluginSinceBuild=233
pluginUntilBuild=233.*
platformVersion=2023.1
platformVersion=2023.3
platformDownloadSources=true

# plugin dependencies (comma-separated)
# example: platformPlugins = com.intellij.java, org.jetbrains.plugins.yaml
# see https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
platformPlugins=org.intellij.plugins.hcl:231.8109.91,org.jetbrains.plugins.yaml,org.jetbrains.kotlin,com.intellij.java,org.intellij.groovy
platformPlugins=org.intellij.plugins.hcl:233.11799.172,org.jetbrains.plugins.yaml,org.jetbrains.kotlin,com.intellij.java,org.intellij.groovy
# list of versions for which to check the plugin for api compatibility
pluginVerifierIdeVersions=2023.1,2023.2,2023.3
pluginVerifierIdeVersions=2023.3
localIdeDirectory=
# opt-out flag for bundling Kotlin standard library
# see https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/io/snyk/plugin/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import io.snyk.plugin.snykcode.core.RunUtils
import io.snyk.plugin.ui.SnykBalloonNotificationHelper
import io.snyk.plugin.ui.toolwindow.SnykToolWindowFactory
import io.snyk.plugin.ui.toolwindow.SnykToolWindowPanel
import org.apache.commons.lang.SystemUtils
import org.apache.commons.lang3.SystemUtils
import snyk.advisor.AdvisorService
import snyk.advisor.AdvisorServiceImpl
import snyk.advisor.SnykAdvisorModel
Expand Down
57 changes: 3 additions & 54 deletions src/main/kotlin/io/snyk/plugin/cli/ConsoleCommandRunner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,11 @@ import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
import com.intellij.util.net.HttpConfigurable
import io.snyk.plugin.controlExternalProcessWithProgressIndicator
import io.snyk.plugin.getWaitForResultsTimeout
import io.snyk.plugin.pluginSettings
import io.snyk.plugin.ui.SnykBalloonNotificationHelper
import snyk.common.getEndpointUrl
import snyk.common.isFedramp
import snyk.common.isOauth
import snyk.common.EnvironmentHelper
import snyk.errorHandler.SentryErrorReporter
import snyk.pluginInfo
import java.net.URI
import java.net.URLEncoder
import java.nio.charset.Charset

open class ConsoleCommandRunner {
Expand Down Expand Up @@ -90,54 +83,10 @@ open class ConsoleCommandRunner {
* Setup environment variables for CLI.
*/
fun setupCliEnvironmentVariables(commandLine: GeneralCommandLine, apiToken: String) {
val endpoint = getEndpointUrl()

val oauthEnabledEnvVar = "INTERNAL_SNYK_OAUTH_ENABLED"
val oauthEnvVar = "INTERNAL_OAUTH_TOKEN_STORAGE"
val snykTokenEnvVar = "SNYK_TOKEN"

val endpointURI = URI(endpoint)
val oauthEnabled = endpointURI.isOauth()
if (oauthEnabled) {
commandLine.environment[oauthEnabledEnvVar] = "1"
commandLine.environment.remove(snykTokenEnvVar)
} else {
commandLine.environment.remove(oauthEnvVar)
commandLine.environment.remove(oauthEnabledEnvVar)
}

if (apiToken.isNotEmpty()) {
if (oauthEnabled) {
commandLine.environment[oauthEnvVar] = apiToken
} else {
commandLine.environment[snykTokenEnvVar] = apiToken
}
}

commandLine.environment["SNYK_API"] = endpoint

if (!pluginSettings().usageAnalyticsEnabled || endpointURI.isFedramp()) {
commandLine.environment["SNYK_CFG_DISABLE_ANALYTICS"] = "1"
}

commandLine.environment["SNYK_INTEGRATION_NAME"] = pluginInfo.integrationName
commandLine.environment["SNYK_INTEGRATION_VERSION"] = pluginInfo.integrationVersion
commandLine.environment["SNYK_INTEGRATION_ENVIRONMENT"] = pluginInfo.integrationEnvironment
commandLine.environment["SNYK_INTEGRATION_ENVIRONMENT_VERSION"] = pluginInfo.integrationEnvironmentVersion
val proxySettings = HttpConfigurable.getInstance()
val proxyHost = proxySettings.PROXY_HOST
if (proxySettings != null && proxySettings.USE_HTTP_PROXY && proxyHost.isNotEmpty()) {
val authentication = if (proxySettings.PROXY_AUTHENTICATION) {
val auth = proxySettings.getPromptedAuthentication(proxyHost, "Snyk: Please enter your proxy password")
if (auth == null) "" else auth.userName.urlEncode() + ":" + String(auth.password).urlEncode() + "@"
} else ""
commandLine.environment["http_proxy"] = "http://$authentication$proxyHost:${proxySettings.PROXY_PORT}"
commandLine.environment["https_proxy"] = "http://$authentication$proxyHost:${proxySettings.PROXY_PORT}"
}
val environment = commandLine.environment
EnvironmentHelper.updateEnvironment(environment, apiToken)
}

private fun String.urlEncode() = URLEncoder.encode(this, "UTF-8")

companion object {
const val PROCESS_CANCELLED_BY_USER = "PROCESS_CANCELLED_BY_USER"
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/io/snyk/plugin/net/TokenInterceptor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import io.snyk.plugin.getWhoamiService
import io.snyk.plugin.pluginSettings
import okhttp3.Interceptor
import okhttp3.Response
import org.apache.commons.lang.SystemUtils
import org.apache.commons.lang3.SystemUtils
import snyk.common.needsSnykToken
import snyk.pluginInfo
import java.time.OffsetDateTime
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import io.snyk.plugin.getSnykCliDownloaderService
import io.snyk.plugin.pluginSettings
import io.snyk.plugin.ui.SnykBalloonNotificationHelper
import io.snyk.plugin.ui.getReadOnlyClickableHtmlJEditorPane
import org.apache.commons.lang.StringEscapeUtils.escapeHtml
import org.apache.commons.text.StringEscapeUtils.escapeHtml4
import snyk.common.getEndpointUrl
import snyk.common.isOauth
import java.awt.BorderLayout
Expand All @@ -35,7 +35,7 @@ import javax.swing.JPanel
import javax.swing.JProgressBar
import javax.swing.ScrollPaneConstants

@Service
@Service(Service.Level.PROJECT)
class SnykCliAuthenticationService(val project: Project) {
private val logger = logger<SnykCliAuthenticationService>()

Expand Down Expand Up @@ -78,7 +78,7 @@ class SnykCliAuthenticationService(val project: Project) {
}
val finalOutput = getConsoleCommandRunner().execute(commands, getPluginPath(), "", project) { line ->
if (line.startsWith("https://")) {
val htmlLink = escapeHtml(line.removeLineEnd())
val htmlLink = escapeHtml4(line.removeLineEnd())
val htmlText =
"""<html>
We are now redirecting you to our auth page, go ahead and log in.<br><br>
Expand Down Expand Up @@ -119,7 +119,7 @@ class SnykCliAuthenticationService(val project: Project) {
token = getConfigApiOutput.removeLineEnd()
}
ProgressManager.getInstance().runProcessWithProgressSynchronously(
getConfigApiTask, "Get Snyk API token", true, null
getConfigApiTask, "Get Snyk API Token", true, null
)
}

Expand All @@ -142,13 +142,13 @@ class SnykCliAuthenticationService(val project: Project) {

class AuthDialog : DialogWrapper(true) {
var onCancel: () -> Unit = {}
private val viewer = getReadOnlyClickableHtmlJEditorPane("Initializing authentication...")
private val viewer = getReadOnlyClickableHtmlJEditorPane("Initializing Authentication...")
val copyUrlAction = CopyUrlAction()

init {
super.init()
copyUrlAction.isEnabled = false
title = "Authenticating Snyk plugin"
title = "Authenticating Snyk Plugin"
}

override fun createCenterPanel(): JComponent {
Expand Down
15 changes: 14 additions & 1 deletion src/main/kotlin/io/snyk/plugin/snykcode/core/SnykCodeFile.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
package io.snyk.plugin.snykcode.core

import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Iconable
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.core.util.toPsiFile
import snyk.common.RelativePathHelper
import javax.swing.Icon

data class SnykCodeFile(val project: Project, val virtualFile: VirtualFile)
data class SnykCodeFile(val project: Project, val virtualFile: VirtualFile) {
var icon: Icon? = null
val relativePath = RelativePathHelper().getRelativePath(virtualFile, project)
init {
ApplicationManager.getApplication().runReadAction {
virtualFile.toPsiFile(project)?.getIcon(Iconable.ICON_FLAG_READ_STATUS)
}
}
}
13 changes: 7 additions & 6 deletions src/main/kotlin/io/snyk/plugin/ui/UIUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import com.intellij.openapi.util.IconLoader
import com.intellij.ui.BrowserHyperlinkListener
import com.intellij.ui.ColorUtil
import com.intellij.ui.ScrollPaneFactory
import com.intellij.ui.components.ActionLink
import com.intellij.uiDesigner.core.GridConstraints
import com.intellij.uiDesigner.core.GridLayoutManager
import com.intellij.uiDesigner.core.Spacer
import com.intellij.util.Alarm
import com.intellij.util.ui.HTMLEditorKitBuilder
import com.intellij.util.ui.JBHtmlEditorKit
import com.intellij.util.ui.JBUI
import com.intellij.util.ui.UIUtil
import io.snyk.plugin.pluginSettings
import io.snyk.plugin.ui.toolwindow.LabelProvider
import org.apache.commons.lang.StringEscapeUtils
import org.apache.commons.text.StringEscapeUtils
import snyk.common.isSnykCodeAvailable
import java.awt.Color
import java.awt.Container
Expand Down Expand Up @@ -242,7 +242,7 @@ fun descriptionHeaderPanel(
cvssV3: String? = null,
id: String? = null,
idUrl: String? = null,
customLabels: List<JLabel> = emptyList()
customLabels: List<ActionLink> = emptyList()
): DescriptionHeaderPanel {
val panel = DescriptionHeaderPanel()
val font14 = getFont(-1, 14, panel.font)
Expand Down Expand Up @@ -297,7 +297,7 @@ class DescriptionHeaderPanel : JPanel()
fun addRowOfItemsToPanel(
panel: JPanel,
startingColumn: Int,
items: List<JLabel>,
items: List<ActionLink>,
separator: String = " | ",
firstSeparator: Boolean = true,
opaqueSeparator: Boolean = true,
Expand Down Expand Up @@ -353,12 +353,13 @@ fun wrapWithScrollPane(panel: JPanel): JScrollPane {
}

fun txtToHtml(s: String): String {
val escapedHtml = StringEscapeUtils.escapeHtml(s)
val escapedHtml = StringEscapeUtils.escapeHtml4(s)
val newLineConverted = escapedHtml
.replace("\n", "<br>")
.replace("\t", "&nbsp; &nbsp; &nbsp;")
// html link converter "stolen" from https://stackoverflow.com/a/12053940/7577274
val str = "(?i)\\b((?:https?://|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'\".,<>?«»“”‘’]))"
val str =
"(?i)\\b((?:https?://|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'\".,<>?«»“”‘’]))"
val patt: Pattern = Pattern.compile(str)
val matcher: Matcher = patt.matcher(newLineConverted)
return matcher.replaceAll("<a href=\"$1\">$1</a>")
Expand Down
Loading

0 comments on commit 8704272

Please sign in to comment.