Browse Source

Fix signing when the developer ID contains non-ASCII characters. (#5358)

pull/5246/merge
Alexander Maryanovsky 5 months ago committed by GitHub
parent
commit
406eef89d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 32
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/MacSigner.kt
  2. 55
      gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/DesktopApplicationTest.kt
  3. 8
      gradle-plugins/compose/src/test/test-projects/application/macSign/build.gradle
  4. BIN
      gradle-plugins/compose/src/test/test-projects/application/macSign/compose.test-non-ascii.keychain
  5. 4
      gradle-plugins/compose/src/test/test-projects/application/macSign/settings.gradle

32
gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/MacSigner.kt

@ -93,7 +93,11 @@ internal class MacSignerImpl(
} }
private fun matchCertificates(certificates: String): String { private fun matchCertificates(certificates: String): String {
val regex = Pattern.compile("\"alis\"<blob>=\"([^\"]+)\"") // When the developer id contains non-ascii characters, the output of `security find-certificate` is
// slightly different. The `alis` line first has the hex-encoded developer id, then some spaces,
// and then the developer id with non-ascii characters encoded as octal.
// See https://bugs.openjdk.org/browse/JDK-8308042
val regex = Pattern.compile("\"alis\"<blob>=(0x[0-9A-F]+)?\\s*\"([^\"]+)\"")
val m = regex.matcher(certificates) val m = regex.matcher(certificates)
if (!m.find()) { if (!m.find()) {
val keychainPath = settings.keychain?.absolutePath val keychainPath = settings.keychain?.absolutePath
@ -102,14 +106,24 @@ internal class MacSignerImpl(
" in keychain [${keychainPath.orEmpty()}]" " in keychain [${keychainPath.orEmpty()}]"
) )
} }
val hexEncoded = m.group(1)
val result = m.group(1) if (hexEncoded.isNullOrBlank()) {
if (m.find()) // Regular case; developer id only has ascii characters
error( val result = m.group(2)
"Multiple matching certificates are found for '${settings.fullDeveloperID}'. " + if (m.find())
"Please specify keychain containing unique matching certificate." error(
) "Multiple matching certificates are found for '${settings.fullDeveloperID}'. " +
return result "Please specify keychain containing unique matching certificate."
)
return result
} else {
return hexEncoded
.substring(2)
.chunked(2)
.map { it.toInt(16).toByte() }
.toByteArray()
.toString(Charsets.UTF_8)
}
} }
} }

55
gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/DesktopApplicationTest.kt

@ -366,19 +366,34 @@ class DesktopApplicationTest : GradlePluginTestBase() {
} }
} }
private fun macSignProject(
identity: String,
keychainFilename: String,
javaVersion: String = "17"
) = testProject("application/macSign").apply {
modifyText("build.gradle") {
it
.replace("%IDENTITY%", identity)
.replace("%KEYCHAIN%", keychainFilename)
.replace("%JAVA_VERSION%", javaVersion)
}
}
@Test @Test
fun testMacSignConfiguration() { fun testMacSignConfiguration() {
Assumptions.assumeTrue(currentOS == OS.MacOS) Assumptions.assumeTrue(currentOS == OS.MacOS)
with(testProject("application/macSign")) { with(macSignProject(identity = "Compose Test", keychainFilename = "compose.test.keychain")) {
gradle("--dry-run", ":createDistributable") gradle("--dry-run", ":createDistributable")
} }
} }
@Test private fun testMacSign(
@Disabled identity: String,
// the test does not work on CI and locally unless test keychain is opened manually keychainFilename: String,
fun testMacSign() { keychainPassword: String,
javaVersion: String = "17"
) {
Assumptions.assumeTrue(currentOS == OS.MacOS) Assumptions.assumeTrue(currentOS == OS.MacOS)
fun security(vararg args: Any): ProcessRunResult { fun security(vararg args: Any): ProcessRunResult {
@ -403,13 +418,12 @@ class DesktopApplicationTest : GradlePluginTestBase() {
} }
} }
with(testProject("application/macSign")) { with(macSignProject(identity = identity, keychainFilename = keychainFilename, javaVersion = javaVersion)) {
val keychain = file("compose.test.keychain") val keychain = file(keychainFilename)
val password = "compose.test"
withNewDefaultKeychain(keychain) { withNewDefaultKeychain(keychain) {
security("default-keychain", "-s", keychain) security("default-keychain", "-s", keychain)
security("unlock-keychain", "-p", password, keychain) security("unlock-keychain", "-p", keychainPassword, keychain)
gradle(":createDistributable").checks { gradle(":createDistributable").checks {
check.taskSuccessful(":createDistributable") check.taskSuccessful(":createDistributable")
@ -431,6 +445,29 @@ class DesktopApplicationTest : GradlePluginTestBase() {
} }
} }
@Test
@Disabled
// the test does not work on CI and locally unless test keychain is opened manually
fun testMacSign() {
testMacSign(
identity = "Compose Test",
keychainFilename = "compose.test.keychain",
keychainPassword = "compose.test"
)
}
@Test
@Disabled
// the test does not work on CI and locally unless test keychain is opened manually
fun testMacSignWithNonAsciiDeveloperId() {
testMacSign(
identity = "Cömpose Test",
keychainFilename = "compose.test-non-ascii.keychain",
keychainPassword = "compose.test",
javaVersion = "21", // https://bugs.openjdk.org/browse/JDK-8308042 fixed in JDK 21
)
}
@Test @Test
fun testOptionsWithSpaces() { fun testOptionsWithSpaces() {
with(testProject("application/optionsWithSpaces")) { with(testProject("application/optionsWithSpaces")) {

8
gradle-plugins/compose/src/test/test-projects/application/macSign/build.gradle

@ -13,14 +13,18 @@ compose.desktop {
application { application {
mainClass = "MainKt" mainClass = "MainKt"
nativeDistributions { nativeDistributions {
javaHome = javaToolchains.launcherFor {
languageVersion.set(JavaLanguageVersion.of(%JAVA_VERSION%))
}.get().metadata.installationPath.asFile.absolutePath
packageName = "TestPackage" packageName = "TestPackage"
macOS { macOS {
bundleID = "signing.test.package" bundleID = "signing.test.package"
signing { signing {
sign.set(true) sign.set(true)
identity.set("Compose Test") identity.set("%IDENTITY%")
keychain.set("compose.test.keychain") keychain.set("%KEYCHAIN%")
} }
} }
} }

BIN
gradle-plugins/compose/src/test/test-projects/application/macSign/compose.test-non-ascii.keychain

Binary file not shown.

4
gradle-plugins/compose/src/test/test-projects/application/macSign/settings.gradle

@ -3,6 +3,7 @@ pluginManagement {
id 'org.jetbrains.kotlin.jvm' version 'KOTLIN_VERSION_PLACEHOLDER' id 'org.jetbrains.kotlin.jvm' version 'KOTLIN_VERSION_PLACEHOLDER'
id 'org.jetbrains.kotlin.plugin.compose' version 'KOTLIN_VERSION_PLACEHOLDER' id 'org.jetbrains.kotlin.plugin.compose' version 'KOTLIN_VERSION_PLACEHOLDER'
id 'org.jetbrains.compose' version 'COMPOSE_GRADLE_PLUGIN_VERSION_PLACEHOLDER' id 'org.jetbrains.compose' version 'COMPOSE_GRADLE_PLUGIN_VERSION_PLACEHOLDER'
id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
} }
repositories { repositories {
mavenLocal() mavenLocal()
@ -14,6 +15,9 @@ pluginManagement {
} }
} }
} }
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
}
dependencyResolutionManagement { dependencyResolutionManagement {
repositories { repositories {
mavenCentral() mavenCentral()

Loading…
Cancel
Save