From 9d084222c49655a224afc92bb782b878f5d3ee47 Mon Sep 17 00:00:00 2001 From: Bastian Doetsch Date: Wed, 4 Oct 2023 11:58:12 +0200 Subject: [PATCH 1/6] feat: add macos arm64 CLI binary name for downloading --- src/main/kotlin/io/snyk/plugin/cli/Platform.kt | 13 +++++++------ src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt | 6 +++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/io/snyk/plugin/cli/Platform.kt b/src/main/kotlin/io/snyk/plugin/cli/Platform.kt index 3f2aec301..a5154b09f 100644 --- a/src/main/kotlin/io/snyk/plugin/cli/Platform.kt +++ b/src/main/kotlin/io/snyk/plugin/cli/Platform.kt @@ -9,23 +9,24 @@ class Platform(val snykWrapperFileName: String) { val LINUX = Platform("snyk-linux") val LINUX_ALPINE = Platform("snyk-alpine") val MAC_OS = Platform("snyk-macos") + val MAC_OS_ARM64 = Platform("snyk-macos-arm64") val WINDOWS = Platform("snyk-win.exe") @Throws(PlatformDetectionException::class) fun current(): Platform = detect(System.getProperties()) - @Suppress("MoveVariableDeclarationIntoWhen") @Throws(PlatformDetectionException::class) fun detect(systemProperties: Properties): Platform { - val architectureName = (systemProperties["os.name"] as String).lowercase() - return when (architectureName) { + val osName = (systemProperties["os.name"] as String).lowercase() + val archName = (systemProperties["os.arch"] as String).lowercase() + return when (osName) { "linux" -> if (Paths.get("/etc/alpine-release").toFile().exists()) LINUX_ALPINE else LINUX - "mac os x", "darwin", "osx" -> MAC_OS + "mac os x", "darwin", "osx" -> if (archName != "aarch64") MAC_OS else MAC_OS_ARM64 else -> { - if (architectureName.contains("windows")) { + if (osName.contains("windows")) { WINDOWS } else { - throw PlatformDetectionException("$architectureName is not supported CPU type") + throw PlatformDetectionException("$osName is not supported CPU type") } } } diff --git a/src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt b/src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt index d048f0f3d..b7b18a065 100644 --- a/src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt +++ b/src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt @@ -2,7 +2,7 @@ package io.snyk.plugin.cli import org.junit.Assert.assertTrue import org.junit.Test -import java.util.* +import java.util.Properties class PlatformTest { @@ -21,6 +21,10 @@ class PlatformTest { properties["os.name"] = "darwin" assertTrue(Platform.MAC_OS == Platform.detect(properties)) + properties["os.name"] = "darwin" + properties["os.arch"] = "aarch64" + assertTrue(Platform.MAC_OS_ARM64 == Platform.detect(properties)) + properties["os.name"] = "osx" assertTrue(Platform.MAC_OS == Platform.detect(properties)) From 4b0e93860a6b6dc4e6f94d91894e36fbc277e442 Mon Sep 17 00:00:00 2001 From: Bastian Doetsch Date: Wed, 4 Oct 2023 11:58:33 +0200 Subject: [PATCH 2/6] feat: add baseURL as parameter to settings --- .../services/SnykApplicationSettingsStateService.kt | 1 + .../snyk/plugin/services/download/CliDownloader.kt | 13 +++++++++---- .../settings/SnykProjectSettingsConfigurable.kt | 4 +++- .../kotlin/io/snyk/plugin/ui/SnykSettingsDialog.kt | 12 ++++++++++++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/io/snyk/plugin/services/SnykApplicationSettingsStateService.kt b/src/main/kotlin/io/snyk/plugin/services/SnykApplicationSettingsStateService.kt index cf11f82cc..b2c73ec30 100644 --- a/src/main/kotlin/io/snyk/plugin/services/SnykApplicationSettingsStateService.kt +++ b/src/main/kotlin/io/snyk/plugin/services/SnykApplicationSettingsStateService.kt @@ -27,6 +27,7 @@ import java.util.UUID ) class SnykApplicationSettingsStateService : PersistentStateComponent { + var cliBaseDownloadURL: String = "https://static.snyk.io" var cliPath: String = getPluginPath() + separator + Platform.current().snykWrapperFileName var manageBinariesAutomatically: Boolean = true var fileListenerEnabled: Boolean = true diff --git a/src/main/kotlin/io/snyk/plugin/services/download/CliDownloader.kt b/src/main/kotlin/io/snyk/plugin/services/download/CliDownloader.kt index 962ba5e50..7f2b83836 100644 --- a/src/main/kotlin/io/snyk/plugin/services/download/CliDownloader.kt +++ b/src/main/kotlin/io/snyk/plugin/services/download/CliDownloader.kt @@ -2,6 +2,7 @@ package io.snyk.plugin.services.download import com.intellij.openapi.progress.ProgressIndicator import io.snyk.plugin.cli.Platform +import io.snyk.plugin.pluginSettings import io.snyk.plugin.services.download.HttpRequestHelper.createRequest import java.io.File import java.nio.file.AtomicMoveNotSupportedException @@ -13,10 +14,14 @@ import javax.xml.bind.DatatypeConverter class CliDownloader { companion object { - const val BASE_URL = "https://static.snyk.io" - const val LATEST_RELEASES_URL = "$BASE_URL/cli/latest/version" - val LATEST_RELEASE_DOWNLOAD_URL = "$BASE_URL/cli/latest/${Platform.current().snykWrapperFileName}" - val SHA256_DOWNLOAD_URL = "$BASE_URL/cli/latest/${Platform.current().snykWrapperFileName}.sha256" + val BASE_URL: String + get() = pluginSettings().cliBaseDownloadURL + val LATEST_RELEASES_URL: String + get() = "$BASE_URL/cli/latest/version" + val LATEST_RELEASE_DOWNLOAD_URL: String + get() = "$BASE_URL/cli/latest/${Platform.current().snykWrapperFileName}" + val SHA256_DOWNLOAD_URL: String + get() = "$BASE_URL/cli/latest/${Platform.current().snykWrapperFileName}.sha256" } fun calculateSha256(bytes: ByteArray): String { diff --git a/src/main/kotlin/io/snyk/plugin/settings/SnykProjectSettingsConfigurable.kt b/src/main/kotlin/io/snyk/plugin/settings/SnykProjectSettingsConfigurable.kt index a6c1bac0e..d32f32ea8 100644 --- a/src/main/kotlin/io/snyk/plugin/settings/SnykProjectSettingsConfigurable.kt +++ b/src/main/kotlin/io/snyk/plugin/settings/SnykProjectSettingsConfigurable.kt @@ -45,7 +45,8 @@ class SnykProjectSettingsConfigurable(val project: Project) : SearchableConfigur snykSettingsDialog.isScanTypeChanged() || snykSettingsDialog.isSeverityEnablementChanged() || snykSettingsDialog.manageBinariesAutomatically() != settingsStateService.manageBinariesAutomatically || - snykSettingsDialog.getCliPath() != settingsStateService.cliPath + snykSettingsDialog.getCliPath() != settingsStateService.cliPath || + snykSettingsDialog.getCliBaseDownloadURL() != settingsStateService.cliBaseDownloadURL private fun isCoreParamsModified() = isTokenModified() || isCustomEndpointModified() || @@ -83,6 +84,7 @@ class SnykProjectSettingsConfigurable(val project: Project) : SearchableConfigur settingsStateService.manageBinariesAutomatically = snykSettingsDialog.manageBinariesAutomatically() settingsStateService.cliPath = snykSettingsDialog.getCliPath().trim() + settingsStateService.cliBaseDownloadURL = snykSettingsDialog.getCliBaseDownloadURL().trim() snykSettingsDialog.saveScanTypeChanges() snykSettingsDialog.saveSeveritiesEnablementChanges() diff --git a/src/main/kotlin/io/snyk/plugin/ui/SnykSettingsDialog.kt b/src/main/kotlin/io/snyk/plugin/ui/SnykSettingsDialog.kt index 61fc4aea6..55bbc99a1 100644 --- a/src/main/kotlin/io/snyk/plugin/ui/SnykSettingsDialog.kt +++ b/src/main/kotlin/io/snyk/plugin/ui/SnykSettingsDialog.kt @@ -78,6 +78,7 @@ class SnykSettingsDialog( private val manageBinariesAutomatically: JCheckBox = JCheckBox() private val cliPathTextBoxWithFileBrowser = TextFieldWithBrowseButton() + private val cliBaseDownloadUrlTextField = JTextField() private val logger = Logger.getInstance(this::class.java) @@ -126,6 +127,7 @@ class SnykSettingsDialog( manageBinariesAutomatically.isSelected = applicationSettings.manageBinariesAutomatically cliPathTextBoxWithFileBrowser.text = applicationSettings.cliPath + cliBaseDownloadUrlTextField.text = applicationSettings.cliBaseDownloadURL additionalParametersTextField.text = applicationSettings.getAdditionalParameters(project) } } @@ -463,6 +465,15 @@ class SnykSettingsDialog( ) ) + cliBaseDownloadUrlTextField.toolTipText = "The default URL is https://static.snyk.io. " + + "for FIPS-enabled CLIs (only available for Windows and Linux), please use https://static.snyk.io/fips" + executableSettingsPanel.add( + UI.PanelFactory + .panel(cliBaseDownloadUrlTextField) + .withLabel("Base URL to download the CLI: ").createPanel(), + gb.nextLine() + ) + cliPathTextBoxWithFileBrowser.toolTipText = "The default path is ${getCliFile().canonicalPath}." val descriptor = FileChooserDescriptor(true, false, false, false, false, false) cliPathTextBoxWithFileBrowser.addBrowseFolderListener( @@ -564,4 +575,5 @@ class SnykSettingsDialog( fun getCliPath(): String = cliPathTextBoxWithFileBrowser.text fun manageBinariesAutomatically() = manageBinariesAutomatically.isSelected + fun getCliBaseDownloadURL(): String = cliBaseDownloadUrlTextField.text } From e507f74cb0222673aecdfe333dfbf67ceb71a339 Mon Sep 17 00:00:00 2001 From: Bastian Doetsch Date: Wed, 4 Oct 2023 12:01:39 +0200 Subject: [PATCH 3/6] docs: updated CHANGELOG.md --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c44a12bd5..12cbe1568 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Snyk Changelog +## [2.5.4] + +### Added + +- support for arm64 CLI on macOS +- support to configure base URL for CLI downloads + ## [2.5.3] ### Fixed From c484f846a2cc75282754c66f3bbeee97932cf70b Mon Sep 17 00:00:00 2001 From: Bastian Doetsch Date: Wed, 4 Oct 2023 12:52:18 +0200 Subject: [PATCH 4/6] fix: tests --- src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt | 1 + .../plugin/services/download/CliDownloaderServiceIntegTest.kt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt b/src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt index b7b18a065..4a89c50c3 100644 --- a/src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt +++ b/src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt @@ -36,6 +36,7 @@ class PlatformTest { fun testDetectPlatformException() { val properties = Properties() properties["os.name"] = "Not supported CPU type" + properties["os.arch"] = "dont care" Platform.detect(properties) } 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 558cb5f98..2c85eb83b 100644 --- a/src/test/kotlin/io/snyk/plugin/services/download/CliDownloaderServiceIntegTest.kt +++ b/src/test/kotlin/io/snyk/plugin/services/download/CliDownloaderServiceIntegTest.kt @@ -98,6 +98,8 @@ class CliDownloaderServiceIntegTest : LightPlatformTestCase() { every { downloader.calculateSha256(any()) } returns "wrong-sha" justRun { errorHandler.handleChecksumVerificationException(any(), any(), any()) } + // this is needed, but I don't know why the config is not picked up from setUp() + every { pluginSettings() } returns SnykApplicationSettingsStateService() cutSpy.downloadLatestRelease(indicator, project) From 4429c62039781adaf5fdffc0b4d4ee14ca0f1e81 Mon Sep 17 00:00:00 2001 From: Bastian Doetsch Date: Wed, 4 Oct 2023 13:06:15 +0200 Subject: [PATCH 5/6] fix: platform test --- src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt b/src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt index 4a89c50c3..757b94d17 100644 --- a/src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt +++ b/src/test/kotlin/io/snyk/plugin/cli/PlatformTest.kt @@ -9,6 +9,7 @@ class PlatformTest { @Test fun testDetectPlatform() { val properties = Properties() + properties["os.arch"] = "something" properties["os.name"] = "linux" @@ -18,6 +19,9 @@ class PlatformTest { properties["os.name"] = "mac os x" assertTrue(Platform.MAC_OS == Platform.detect(properties)) + properties["os.name"] = "osx" + assertTrue(Platform.MAC_OS == Platform.detect(properties)) + properties["os.name"] = "darwin" assertTrue(Platform.MAC_OS == Platform.detect(properties)) @@ -25,9 +29,6 @@ class PlatformTest { properties["os.arch"] = "aarch64" assertTrue(Platform.MAC_OS_ARM64 == Platform.detect(properties)) - properties["os.name"] = "osx" - assertTrue(Platform.MAC_OS == Platform.detect(properties)) - properties["os.name"] = "windows" assertTrue(Platform.WINDOWS == Platform.detect(properties)) } From 8109031bd195b1e8b45456e28957eb5dabdd7c70 Mon Sep 17 00:00:00 2001 From: Bastian Doetsch Date: Wed, 4 Oct 2023 13:08:48 +0200 Subject: [PATCH 6/6] fix: CliDownloaderTest --- .../io/snyk/plugin/services/download/CliDownloaderTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/kotlin/io/snyk/plugin/services/download/CliDownloaderTest.kt b/src/test/kotlin/io/snyk/plugin/services/download/CliDownloaderTest.kt index 6b38743f6..a63ae32d7 100644 --- a/src/test/kotlin/io/snyk/plugin/services/download/CliDownloaderTest.kt +++ b/src/test/kotlin/io/snyk/plugin/services/download/CliDownloaderTest.kt @@ -75,7 +75,7 @@ class CliDownloaderTest { val expectedSha = cut.calculateSha256("wrong sha".toByteArray()) mockCliDownload() - + every { pluginSettings() } returns SnykApplicationSettingsStateService() try { cut.downloadFile(testFile, expectedSha, mockk(relaxed = true)) fail("Should have thrown ChecksumVerificationException")