From fa4815915ddf0f8ff40f71bf38098bd62b7e6f8d Mon Sep 17 00:00:00 2001 From: Matthew Barbara Date: Mon, 11 Sep 2023 10:01:52 +0200 Subject: [PATCH] feat: Enabling SCLE [NEBULA-1371] (#447) * feat: Enabling SCLE * fix: PR feedback update #1 * fix: PR feedback update #2 * testing... * fix: breaking tests, better UX * fix: unit tests * fix: updated with PR feedback * fix: text when SAST setting is misconigured Signed-off-by: Matthew Barbara * fix: lint Signed-off-by: Matthew Barbara * fix: Added changes in changelog.md Signed-off-by: Matthew Barbara * fix: lint Signed-off-by: Matthew Barbara --------- Signed-off-by: Matthew Barbara --- CHANGELOG.md | 6 ++ src/main/kotlin/io/snyk/plugin/Utils.kt | 8 ++- .../io/snyk/plugin/net/CliConfigService.kt | 16 ++++- .../io/snyk/plugin/net/SnykApiClient.kt | 18 ++++++ .../SnykApplicationSettingsStateService.kt | 2 + .../plugin/services/SnykTaskQueueService.kt | 24 ++++---- .../plugin/ui/SnykBalloonNotifications.kt | 13 ---- src/main/kotlin/io/snyk/plugin/ui/UIUtils.kt | 8 +-- .../snyk/plugin/ui/settings/ScanTypesPanel.kt | 34 +++++++---- .../ui/toolwindow/SnykToolWindowPanel.kt | 10 +++- .../kotlin/snyk/common/CustomEndpoints.kt | 14 ++++- .../services/SnykTaskQueueServiceTest.kt | 28 +-------- .../ui/toolwindow/SnykToolWindowPanelTest.kt | 32 +++++++++- .../api/AmplitudeExperimentApiClientTest.kt | 8 +++ .../kotlin/snyk/code/DeepCodeRestApiTest.kt | 6 ++ .../kotlin/snyk/common/CustomEndpointsTest.kt | 60 +++++++++++++++++-- 16 files changed, 202 insertions(+), 85 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6adac01c7..f7f4a3032 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Snyk Changelog +## [2.5.2] + +### Added + +- Snyk Code support for on-prem solutions (Snyk Code Local Engine) + ## [2.5.1] ### Changed diff --git a/src/main/kotlin/io/snyk/plugin/Utils.kt b/src/main/kotlin/io/snyk/plugin/Utils.kt index b6ca4031e..2456a9151 100644 --- a/src/main/kotlin/io/snyk/plugin/Utils.kt +++ b/src/main/kotlin/io/snyk/plugin/Utils.kt @@ -24,6 +24,7 @@ import com.intellij.psi.PsiManager import com.intellij.util.Alarm import com.intellij.util.FileContentUtil import com.intellij.util.messages.Topic +import io.snyk.plugin.net.ClientException import io.snyk.plugin.services.SnykAnalyticsService import io.snyk.plugin.services.SnykApiService import io.snyk.plugin.services.SnykApplicationSettingsStateService @@ -193,7 +194,12 @@ fun startSastEnablementCheckLoop(parentDisposable: Disposable, onSuccess: () -> lateinit var checkIfSastEnabled: () -> Unit checkIfSastEnabled = { if (settings.sastOnServerEnabled != true) { - settings.sastOnServerEnabled = getSnykApiService().getSastSettings()?.sastEnabled ?: false + settings.sastOnServerEnabled = try { + getSnykApiService().getSastSettings()?.sastEnabled ?: false + } catch (ignored: ClientException) { + false + } + if (settings.sastOnServerEnabled == true) { onSuccess.invoke() } else if (!alarm.isDisposed && currentAttempt < maxAttempts) { diff --git a/src/main/kotlin/io/snyk/plugin/net/CliConfigService.kt b/src/main/kotlin/io/snyk/plugin/net/CliConfigService.kt index e7063c4b5..09cb88de7 100644 --- a/src/main/kotlin/io/snyk/plugin/net/CliConfigService.kt +++ b/src/main/kotlin/io/snyk/plugin/net/CliConfigService.kt @@ -28,10 +28,24 @@ data class CliConfigSettings( val reportFalsePositivesEnabled: Boolean ) +data class CliConfigSettingsError( + @SerializedName("userMessage") + val userMessage: String, + + @SerializedName("code") + val code: Int? +) + /** * SAST local code engine configuration. */ data class LocalCodeEngine( @SerializedName("enabled") - val enabled: Boolean + val enabled: Boolean, + + @SerializedName("url") + val url: String, + + @SerializedName("allowCloudUpload") + val allowCloudUpload: Boolean ) diff --git a/src/main/kotlin/io/snyk/plugin/net/SnykApiClient.kt b/src/main/kotlin/io/snyk/plugin/net/SnykApiClient.kt index f8d268268..1483322be 100644 --- a/src/main/kotlin/io/snyk/plugin/net/SnykApiClient.kt +++ b/src/main/kotlin/io/snyk/plugin/net/SnykApiClient.kt @@ -1,6 +1,8 @@ package io.snyk.plugin.net +import com.google.gson.Gson import com.intellij.openapi.diagnostic.logger +import io.ktor.http.HttpStatusCode import retrofit2.Call import retrofit2.Retrofit @@ -29,11 +31,25 @@ class SnykApiClient( log.debug("Executing request to $apiName") val response = retrofitCall.execute() if (!response.isSuccessful) { + if (response.code() == HttpStatusCode.UnprocessableEntity.value) { + val responseBodyString = response.errorBody()?.string() + val errorBody = Gson().fromJson( + responseBodyString, + CliConfigSettingsError::class.java + ) + if (errorBody?.userMessage?.isNotEmpty() == true) { + throw ClientException(errorBody.userMessage) + } + return null + } log.warn("Failed to execute `$apiName` call: ${response.errorBody()?.string()}") executeRequest(apiName, retrofitCall.clone(), retryCounter - 1) } else { response.body() } + } catch (t: ClientException) { + // Consumers are expected to handle ClientException throws. + throw t } catch (t: Throwable) { log.warn("Failed to execute '$apiName' network request: ${t.message}", t) executeRequest(apiName, retrofitCall.clone(), retryCounter - 1) @@ -44,3 +60,5 @@ class SnykApiClient( private val log = logger() } } + +class ClientException(userMessage: String) : RuntimeException(userMessage) diff --git a/src/main/kotlin/io/snyk/plugin/services/SnykApplicationSettingsStateService.kt b/src/main/kotlin/io/snyk/plugin/services/SnykApplicationSettingsStateService.kt index 0d003443f..cf11f82cc 100644 --- a/src/main/kotlin/io/snyk/plugin/services/SnykApplicationSettingsStateService.kt +++ b/src/main/kotlin/io/snyk/plugin/services/SnykApplicationSettingsStateService.kt @@ -48,7 +48,9 @@ class SnykApplicationSettingsStateService : PersistentStateComponent { - if (settings.localCodeEngineEnabled == true) { - SnykBalloonNotifications.showSastForLocalCodeEngineMessage(project) - scanPublisher?.scanningSnykCodeError( - SnykError( - SnykBalloonNotifications.sastForLocalCodeEngineMessage, project.basePath ?: "" - ) - ) - settings.snykCodeSecurityIssuesScanEnable = false - settings.snykCodeQualityIssuesScanEnable = false - } else { - getSnykCode(project)?.scan() - scanPublisher?.scanningStarted() - } + getSnykCode(project)?.scan() + scanPublisher?.scanningStarted() } false -> { diff --git a/src/main/kotlin/io/snyk/plugin/ui/SnykBalloonNotifications.kt b/src/main/kotlin/io/snyk/plugin/ui/SnykBalloonNotifications.kt index c3a61cbed..702def721 100644 --- a/src/main/kotlin/io/snyk/plugin/ui/SnykBalloonNotifications.kt +++ b/src/main/kotlin/io/snyk/plugin/ui/SnykBalloonNotifications.kt @@ -25,8 +25,6 @@ object SnykBalloonNotifications { private val logger = logger() private val alarm = Alarm() - const val sastForLocalCodeEngineMessage = "Snyk Code is configured to use a Local Code Engine instance." + - "This setup is not yet supported." const val sastForOrgEnablementMessage = "Snyk Code is disabled by your organisation's configuration." const val networkErrorAlertMessage = "Not able to connect to Snyk server." @@ -46,17 +44,6 @@ object SnykBalloonNotifications { notification.notify(project) } - fun showSastForLocalCodeEngineMessage(project: Project): Notification { - return SnykBalloonNotificationHelper.showInfo( - sastForLocalCodeEngineMessage, - project, - NotificationAction.createSimpleExpiring("SNYK SETTINGS") { - ShowSettingsUtil.getInstance() - .showSettingsDialog(project, SnykProjectSettingsConfigurable::class.java) - } - ) - } - fun showSastForOrgEnablement(project: Project): Notification { val notification = SnykBalloonNotificationHelper.showInfo( "$sastForOrgEnablementMessage To enable navigate to ", diff --git a/src/main/kotlin/io/snyk/plugin/ui/UIUtils.kt b/src/main/kotlin/io/snyk/plugin/ui/UIUtils.kt index 7be40954d..d6accd5fb 100644 --- a/src/main/kotlin/io/snyk/plugin/ui/UIUtils.kt +++ b/src/main/kotlin/io/snyk/plugin/ui/UIUtils.kt @@ -96,12 +96,12 @@ fun insertTitleAndResizableTextIntoPanelColumns( fun snykCodeAvailabilityPostfix(): String { val sastOnServerEnabled = pluginSettings().sastOnServerEnabled - val localCodeEngineEnabled = pluginSettings().localCodeEngineEnabled + val sastSettingsError = pluginSettings().sastSettingsError return when { + sastSettingsError == true -> " (Snyk Code settings misconfigured)" + sastOnServerEnabled == false -> " (disabled in Snyk.io)" !isSnykCodeAvailable(pluginSettings().customEndpointUrl) -> " (disabled for endpoint)" - (sastOnServerEnabled == null && localCodeEngineEnabled == null) -> " (unreachable server settings)" - (sastOnServerEnabled != false && localCodeEngineEnabled == true) -> " (disabled due to Local Code Engine)" - sastOnServerEnabled != true -> " (disabled in Snyk.io)" + sastOnServerEnabled == null -> " (unreachable server settings)" else -> "" } } diff --git a/src/main/kotlin/io/snyk/plugin/ui/settings/ScanTypesPanel.kt b/src/main/kotlin/io/snyk/plugin/ui/settings/ScanTypesPanel.kt index ce23fd1b5..7370c659f 100644 --- a/src/main/kotlin/io/snyk/plugin/ui/settings/ScanTypesPanel.kt +++ b/src/main/kotlin/io/snyk/plugin/ui/settings/ScanTypesPanel.kt @@ -16,6 +16,8 @@ import io.snyk.plugin.getKubernetesImageCache import io.snyk.plugin.getSnykApiService import io.snyk.plugin.isContainerEnabled import io.snyk.plugin.isIacEnabled +import io.snyk.plugin.net.CliConfigSettings +import io.snyk.plugin.net.ClientException import io.snyk.plugin.pluginSettings import io.snyk.plugin.snykcode.core.SnykCodeUtils import io.snyk.plugin.startSastEnablementCheckLoop @@ -219,25 +221,33 @@ class ScanTypesPanel( return } + var sastSettingsError: String = "" + val sastCliConfigSettings: CliConfigSettings? = try { + val sastSettings = getSnykApiService().getSastSettings() + settings.sastSettingsError = false + sastSettings + } catch (t: ClientException) { + settings.sastSettingsError = true + val defaultErrorMsg = "Your org's SAST settings are misconfigured." + val userMessage = if (t.message.isNullOrEmpty()) defaultErrorMsg else t.message!! + SnykBalloonNotificationHelper.showError(userMessage, null) + sastSettingsError = userMessage + null + } + + settings.sastOnServerEnabled = sastCliConfigSettings?.sastEnabled + settings.localCodeEngineEnabled = sastCliConfigSettings?.localCodeEngine?.enabled + settings.localCodeEngineUrl = sastCliConfigSettings?.localCodeEngine?.url val snykCodeAvailable = isSnykCodeAvailable(settings.customEndpointUrl) showSnykCodeAlert( - if (snykCodeAvailable) "" else "Snyk Code only works in SAAS mode (i.e. no Custom Endpoint usage)" + sastSettingsError.ifEmpty { "" } ) if (snykCodeAvailable) { setSnykCodeComment(progressMessage = "Checking if Snyk Code enabled for organisation...") { - val sastCliConfigSettings = getSnykApiService().getSastSettings() - settings.sastOnServerEnabled = sastCliConfigSettings?.sastEnabled - settings.localCodeEngineEnabled = sastCliConfigSettings?.localCodeEngine?.enabled + when (settings.sastOnServerEnabled) { true -> { - if (settings.localCodeEngineEnabled == true) { - showSnykCodeAlert( - message = "Snyk Code is configured to use a Local Code Engine instance." + - " This setup is not yet supported." - ) - } else { - doShowFilesToUpload() - } + doShowFilesToUpload() } false -> { diff --git a/src/main/kotlin/io/snyk/plugin/ui/toolwindow/SnykToolWindowPanel.kt b/src/main/kotlin/io/snyk/plugin/ui/toolwindow/SnykToolWindowPanel.kt index f46bf6ccf..3175989a6 100644 --- a/src/main/kotlin/io/snyk/plugin/ui/toolwindow/SnykToolWindowPanel.kt +++ b/src/main/kotlin/io/snyk/plugin/ui/toolwindow/SnykToolWindowPanel.kt @@ -43,6 +43,7 @@ import io.snyk.plugin.isOssRunning import io.snyk.plugin.isScanRunning import io.snyk.plugin.isSnykCodeRunning import io.snyk.plugin.navigateToSource +import io.snyk.plugin.net.ClientException import io.snyk.plugin.pluginSettings import io.snyk.plugin.refreshAnnotationsForOpenFiles import io.snyk.plugin.snykToolWindow @@ -488,10 +489,13 @@ class SnykToolWindowPanel(val project: Project) : JPanel(), Disposable { private fun enableCodeScanAccordingToServerSetting() { pluginSettings().apply { - val sastSettings = getSnykApiService().getSastSettings() + val sastSettings = try { + getSnykApiService().getSastSettings() + } catch (ignored: ClientException) { + null + } sastOnServerEnabled = sastSettings?.sastEnabled - localCodeEngineEnabled = sastSettings?.localCodeEngine?.enabled - val codeScanAllowed = sastOnServerEnabled == true && localCodeEngineEnabled != true + val codeScanAllowed = sastOnServerEnabled == true snykCodeSecurityIssuesScanEnable = this.snykCodeSecurityIssuesScanEnable && codeScanAllowed snykCodeQualityIssuesScanEnable = this.snykCodeQualityIssuesScanEnable && codeScanAllowed } diff --git a/src/main/kotlin/snyk/common/CustomEndpoints.kt b/src/main/kotlin/snyk/common/CustomEndpoints.kt index 558b3742f..564d6204a 100644 --- a/src/main/kotlin/snyk/common/CustomEndpoints.kt +++ b/src/main/kotlin/snyk/common/CustomEndpoints.kt @@ -1,8 +1,8 @@ package snyk.common import io.snyk.plugin.pluginSettings -import io.snyk.plugin.prefixIfNot import io.snyk.plugin.suffixIfNot +import io.snyk.plugin.prefixIfNot import java.net.URI import java.net.URISyntaxException @@ -12,6 +12,9 @@ fun toSnykCodeApiUrl(endpointUrl: String?): String { val codeSubdomain = "deeproxy" val snykCodeApiUrl = when { + uri.isLocalCodeEngine() -> + return pluginSettings().localCodeEngineUrl!! + uri.isDeeproxy() -> endpoint @@ -29,7 +32,10 @@ fun toSnykCodeApiUrl(endpointUrl: String?): String { fun toSnykCodeSettingsUrl(endpointUrl: String?): String { val endpoint = resolveCustomEndpoint(endpointUrl) val uri = URI(endpoint) + val baseUrl = when { + uri.isLocalCodeEngine() -> return uri.toString() + uri.host == "snyk.io" -> "https://app.snyk.io/" @@ -50,7 +56,7 @@ fun toSnykCodeSettingsUrl(endpointUrl: String?): String { fun needsSnykToken(endpoint: String): Boolean { val uri = URI(endpoint) - return uri.isSnykApi() || uri.isSnykTenant() || uri.isDeeproxy() + return uri.isSnykApi() || uri.isSnykTenant() || uri.isDeeproxy() || uri.isLocalCodeEngine() } fun getEndpointUrl(): String { @@ -67,7 +73,7 @@ fun getEndpointUrl(): String { fun isSnykCodeAvailable(endpointUrl: String?): Boolean { val endpoint = resolveCustomEndpoint(endpointUrl) val uri = URI(endpoint) - return uri.isSnykTenant() + return uri.isSnykTenant() || uri.isLocalCodeEngine() } /** @@ -129,6 +135,8 @@ fun isFedramp(): Boolean { ?.isFedramp() ?: false } +fun URI.isLocalCodeEngine() = pluginSettings().localCodeEngineEnabled == true + internal fun String.removeTrailingSlashesIfPresent(): String { val candidate = this.replace(Regex("/+$"), "") return try { diff --git a/src/test/kotlin/io/snyk/plugin/services/SnykTaskQueueServiceTest.kt b/src/test/kotlin/io/snyk/plugin/services/SnykTaskQueueServiceTest.kt index 60902bed4..fbf126a96 100644 --- a/src/test/kotlin/io/snyk/plugin/services/SnykTaskQueueServiceTest.kt +++ b/src/test/kotlin/io/snyk/plugin/services/SnykTaskQueueServiceTest.kt @@ -66,12 +66,12 @@ class SnykTaskQueueServiceTest : LightPlatformTestCase() { snykApiServiceMock = mockk() every { snykApiServiceMock.getSastSettings() } returns CliConfigSettings( true, - LocalCodeEngine(false), + LocalCodeEngine(false, "", false), false ) every { snykApiServiceMock.getSastSettings() } returns CliConfigSettings( true, - LocalCodeEngine(false), + LocalCodeEngine(false, "", false), false ) } @@ -187,30 +187,6 @@ class SnykTaskQueueServiceTest : LightPlatformTestCase() { assertNull(settings.localCodeEngineEnabled) } - fun `test should disable Code settings when LCE is enabled`() { - val snykTaskQueueService = project.service() - val settings = pluginSettings() - settings.sastOnServerEnabled = true - settings.localCodeEngineEnabled = true - settings.snykCodeQualityIssuesScanEnable = true - settings.snykCodeSecurityIssuesScanEnable = true - settings.token = "testToken" - // overwrite default setup - snykApiServiceMock = mockk(relaxed = true) - replaceSnykApiServiceMockInContainer() - every { snykApiServiceMock.getSastSettings() } returns CliConfigSettings( - true, - LocalCodeEngine(true), - false - ) - - snykTaskQueueService.scan() - PlatformTestUtil.dispatchAllInvocationEventsInIdeEventQueue() - - assertThat(settings.snykCodeSecurityIssuesScanEnable, equalTo(false)) - assertThat(settings.snykCodeQualityIssuesScanEnable, equalTo(false)) - } - private fun replaceSnykApiServiceMockInContainer() { val application = ApplicationManager.getApplication() application.replaceService(SnykApiService::class.java, snykApiServiceMock, application) diff --git a/src/test/kotlin/io/snyk/plugin/ui/toolwindow/SnykToolWindowPanelTest.kt b/src/test/kotlin/io/snyk/plugin/ui/toolwindow/SnykToolWindowPanelTest.kt index ac57f0bac..b15708b35 100644 --- a/src/test/kotlin/io/snyk/plugin/ui/toolwindow/SnykToolWindowPanelTest.kt +++ b/src/test/kotlin/io/snyk/plugin/ui/toolwindow/SnykToolWindowPanelTest.kt @@ -124,7 +124,7 @@ class SnykToolWindowPanelTest : LightPlatform4TestCase() { every { settings.pluginFirstRun } returns true every { snykApiServiceMock.getSastSettings() } returns CliConfigSettings( true, - LocalCodeEngine(false), + LocalCodeEngine(false, "", false), false ) justRun { taskQueueService.scan() } @@ -144,7 +144,35 @@ class SnykToolWindowPanelTest : LightPlatform4TestCase() { fun `should automatically enable all products on first run after Auth`() { every { snykApiServiceMock.getSastSettings() } returns CliConfigSettings( true, - LocalCodeEngine(false), + LocalCodeEngine(false, "", false), + false + ) + val application = ApplicationManager.getApplication() + application.replaceService( + SnykApplicationSettingsStateService::class.java, + SnykApplicationSettingsStateService(), + application + ) + pluginSettings().token = "test-token" + pluginSettings().pluginFirstRun = true + + SnykToolWindowPanel(project) + + verify(exactly = 1, timeout = 5000) { + snykApiServiceMock.getSastSettings() + } + assertTrue(pluginSettings().ossScanEnable) + assertTrue(pluginSettings().snykCodeSecurityIssuesScanEnable) + assertTrue(pluginSettings().snykCodeQualityIssuesScanEnable) + assertTrue(pluginSettings().iacScanEnabled) + assertTrue(pluginSettings().containerScanEnabled) + } + + @Test + fun `should automatically enable all products on first run after Auth, with local engine enabled`() { + every { snykApiServiceMock.getSastSettings() } returns CliConfigSettings( + true, + LocalCodeEngine(true, "http://foo.bar/api", false), false ) val application = ApplicationManager.getApplication() diff --git a/src/test/kotlin/snyk/amplitude/api/AmplitudeExperimentApiClientTest.kt b/src/test/kotlin/snyk/amplitude/api/AmplitudeExperimentApiClientTest.kt index b9b328b5d..317cf3637 100644 --- a/src/test/kotlin/snyk/amplitude/api/AmplitudeExperimentApiClientTest.kt +++ b/src/test/kotlin/snyk/amplitude/api/AmplitudeExperimentApiClientTest.kt @@ -1,9 +1,11 @@ package snyk.amplitude.api import io.mockk.every +import io.mockk.mockk import io.mockk.mockkStatic import io.mockk.unmockkAll import io.snyk.plugin.pluginSettings +import io.snyk.plugin.services.SnykApplicationSettingsStateService import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer import okio.buffer @@ -54,6 +56,8 @@ class AmplitudeExperimentApiClientTest { @Test fun `sdkVardata should return 200 by multiple variants`() { + val settings = mockk(relaxed = true) + every { pluginSettings() } returns settings server.enqueueResponse("sdk-vardata_multiple-variants_200.json", 200) val amplitudeVariantService = clientUnderTest.variantService() @@ -79,6 +83,8 @@ class AmplitudeExperimentApiClientTest { @Test fun `sdkVardata should return 200 by empty user id`() { + val settings = mockk(relaxed = true) + every { pluginSettings() } returns settings server.enqueueResponse("sdk-vardata_empty-response_200.json", 200) val amplitudeVariantService = clientUnderTest.variantService() @@ -89,6 +95,8 @@ class AmplitudeExperimentApiClientTest { @Test fun `allVariants should return multiple variants`() { + val settings = mockk(relaxed = true) + every { pluginSettings() } returns settings server.enqueueResponse("sdk-vardata_multiple-variants_200.json", 200) val actualVariants = clientUnderTest.allVariants(ExperimentUser("random-user-id")) diff --git a/src/test/kotlin/snyk/code/DeepCodeRestApiTest.kt b/src/test/kotlin/snyk/code/DeepCodeRestApiTest.kt index 86d7e222f..4ed55f184 100644 --- a/src/test/kotlin/snyk/code/DeepCodeRestApiTest.kt +++ b/src/test/kotlin/snyk/code/DeepCodeRestApiTest.kt @@ -19,6 +19,7 @@ import io.mockk.mockk import io.mockk.mockkStatic import io.mockk.unmockkAll import io.snyk.plugin.pluginSettings +import io.snyk.plugin.services.SnykApplicationSettingsStateService import io.snyk.plugin.snykcode.newCodeRestApi import org.junit.After import org.junit.Assert @@ -368,10 +369,15 @@ class DeepCodeRestApiImplTest { @Test fun snykCodeAnalysis_smoke_test() { + // This test will fail on your local machine, unless you have a valid prod `SNYK_TOKEN` unmockkAll() mockkStatic("io.snyk.plugin.UtilsKt") + val settings = mockk(relaxed = true) + every { pluginSettings() } returns settings every { pluginSettings().token } returns loggedToken + every { pluginSettings().localCodeEngineEnabled } returns false every { pluginSettings().ignoreUnknownCA } returns false + mockkStatic("snyk.PluginInformationKt") every { pluginInfo } returns mockk(relaxed = true) diff --git a/src/test/kotlin/snyk/common/CustomEndpointsTest.kt b/src/test/kotlin/snyk/common/CustomEndpointsTest.kt index 09e5a4d80..8f435e31f 100644 --- a/src/test/kotlin/snyk/common/CustomEndpointsTest.kt +++ b/src/test/kotlin/snyk/common/CustomEndpointsTest.kt @@ -1,13 +1,34 @@ package snyk.common +import io.mockk.mockk +import io.mockk.every +import io.mockk.mockkStatic +import io.mockk.unmockkAll import junit.framework.TestCase.assertFalse import junit.framework.TestCase.assertTrue +import junit.framework.TestCase.assertEquals import org.hamcrest.core.IsEqual.equalTo import org.junit.Assert.assertThat import org.junit.Test +import org.junit.Before import java.net.URI +import io.snyk.plugin.pluginSettings +import io.snyk.plugin.services.SnykApplicationSettingsStateService +import org.junit.After class CustomEndpointsTest { + @Before + fun setUp() { + unmockkAll() + mockkStatic("io.snyk.plugin.UtilsKt") + val settings = mockk(relaxed = true) + every { pluginSettings() } returns settings + } + + @After + fun tearDown() { + unmockkAll() + } @Test fun `resolveCustomEndpoint returns production SaaS url if endpointUrl is null or empty`() { @@ -44,17 +65,18 @@ class CustomEndpointsTest { } @Test - fun `isSnykCodeAvailable returns true for Single Tenant deployments`() { - val snykCodeAvailable = isSnykCodeAvailable("https://app.random-uuid.snyk.io/api") + fun `isSnykCodeAvailable returns true if local engine is enabled`() { + every { pluginSettings().localCodeEngineUrl } returns "http://foo.bar/api" + every { pluginSettings().localCodeEngineEnabled } returns true - assertThat(snykCodeAvailable, equalTo(true)) + assertEquals(isSnykCodeAvailable("https://foo.bar/api"), true) } @Test - fun `isSnykCodeAvailable returns false for OnPremises deployments`() { - val snykCodeAvailable = isSnykCodeAvailable("https://on-prem.internal/api") + fun `isSnykCodeAvailable returns true for Single Tenant deployments`() { + val snykCodeAvailable = isSnykCodeAvailable("https://app.random-uuid.snyk.io/api") - assertThat(snykCodeAvailable, equalTo(false)) + assertThat(snykCodeAvailable, equalTo(true)) } @Test @@ -74,6 +96,15 @@ class CustomEndpointsTest { assertThat(apiUrlForDevelopment, equalTo("https://deeproxy.dev.snyk.io/")) } + @Test + fun `toSnykCodeApiUrl returns local engine URL if local engine is enabled`() { + every { pluginSettings().localCodeEngineUrl } returns "http://foo.bar/api" + every { pluginSettings().localCodeEngineEnabled } returns true + val apiUrlForProduction = toSnykCodeApiUrl("https://snyk.io/api") + + assertEquals(apiUrlForProduction, "http://foo.bar/api") + } + @Test fun `toSnykCodeApiUrl returns correct deeproxy url for SaaS deployments using api url`() { val apiUrlForProduction = toSnykCodeApiUrl("https://app.eu.snyk.io/api") @@ -104,6 +135,14 @@ class CustomEndpointsTest { ) } + @Test + fun `toSnykCodeSettingsUrl returns URL unedited for local engine`() { + every { pluginSettings().localCodeEngineUrl } returns "http://foo.bar/api" + every { pluginSettings().localCodeEngineEnabled } returns true + + assertEquals(toSnykCodeSettingsUrl("http://foo.bar/api"), "http://foo.bar/api") + } + @Test fun `toSnykCodeSettingsUrl returns correct settings url for Single Tenant deployments`() { val settingsUrl = toSnykCodeSettingsUrl("https://app.random-uuid.snyk.io/api") @@ -157,6 +196,15 @@ class CustomEndpointsTest { assertTrue(needsSnykToken(uri)) } + @Test + fun `needsSnykToken return true if local-engine is enabled`() { + every { pluginSettings().localCodeEngineUrl } returns "http://foo.bar" + every { pluginSettings().localCodeEngineEnabled } returns true + val uri = "https://foo.bar/api" + + assertEquals(needsSnykToken(uri), true) + } + @Test fun `isOauth true for the right URI`() { val uri = URI("https://app.xxx.snykgov.io")