I followed <this guide> to publish a compose app t...
# compose-desktop
s
I followed this guide to publish a compose app to the mac appstore, but running packagePkg fails with
Copy code
Execution failed for task ':composeApp:createDistributable'.
> Could not find certificate for 'Dominik Sö' in keychain [/Users/domin/Library/Keychains/login.keychain-db]
I created both certificates, downloaded and installed them. I can see them in the Keychain access app as well as in the terminal, so what could be going wrong here?
Copy code
signing {
    sign.set(true)
    identity.set("Dominik Sö")
    keychain.set("/Users/domin/Library/Keychains/login.keychain-db")
}
m
For me the identity name is longer and starts with
Developer ID Application: …
and you also don’t have to specify the (default) keychain explicitly.
s
the thing is, the guide said for appstore signing you need two certificates,
3rd Party Mac Developer Application
and
3rd Party Mac Developer Installer
.
Developer ID Application
is only for publishing outside of App store. I can test it with each one but don't see a way of providing multiple.
and in the keychain app, your legal name is also the
name
property of the keys, so it looks like providing that should work
sadly that doesn't change anything, I still get the same error
r
Not specific to Kotlin, but your certificate request has to be created with a private key, and the downloaded certificate has to be in the same keychain as that private key in order to be considered valid. Idk if that's it exactly, but perhaps. It may also be related to how the system handles special characters such as whitespace or
ö
when searching for a certificate, but I'm not totally sure.
s
I created the certificate request with the keychain access app so I think that should be fine. About the ö, I created a manual gradle task like this that did actually work.
Copy code
tasks.register<Exec>("signMacPkg") {

    val pkgPath = layout.buildDirectory.file(
        "compose/binaries/main/pkg/App.pkg"
    ).get().asFile.absolutePath

    val identity = "Dominik Sö"
    val keychainPath = "/Users/domin/Library/Keychains/login.keychain-db"

    commandLine(
        "productsign",
        "--sign", identity,
        "--keychain", keychainPath,
        pkgPath,
        pkgPath.replace(".pkg", "-signed.pkg")
    )
}
Copy code
productsign: signing product with identity "3rd Party Mac Developer Installer: DOMINIK SÖ (team number#)" from keychain /Users/domin/Library/Keychains/login.keychain-db
productsign: adding certificate "Apple Worldwide Developer Relations Certification Authority"
productsign: adding certificate "Apple Root CA"
productsign: Wrote signed product archive to /Users/domin/IdeaProjects/App/composeApp/build/compose/binaries/main/pkg/App-signed.pkg
I found this issue https://youtrack.jetbrains.com/issues/CMP?q=%7Bcould%20not%20find%20certificate%7D&amp;preview=CMP-4272 and tried to create a separate keychain with only the two needed certificates but same result. Ofc the find-certificate commands when I execute them are still working perfectly fine
m
I don’t know whether this is related and of any help but when I first set up the certificates for notarization I had to manually download two missing certificates from an Apple server to make my own one valid. I can’t remember them anymore now but I think it were the ones I see above which were added by productsign. I was wondering at that time why these were not coming directly with XCode but maybe they are downloaded if you use the apple tooling but not when you use the compose tooling. Just a wild guess but maybe it rings a bell somewhere.
s
Do you mean the Apple Worldwide Developer stuff? I do have them on my system and also adding them to the custom keychain sadly doesn't help.
m
Yes, I think that was it.
s
oh I think I found the issue
Copy code
[org.gradle.process.internal.DefaultExecHandle] Starting process 'command '/usr/bin/security''. Working directory: /Users/domin/IdeaProjects/ClubManager/composeApp Command: /usr/bin/security find-certificate -a -c 3rd Party Mac Developer Application: Dominik Sö
running this exact command doesn't work for me either, but when I put the certificate string in "" it works
I left a comment here. Tldr: commandline arguments should be in quotes. How likely is it that a fix would make it to a near dev version? I'm unable to publish any app to the AppStore due to this. (https://github.com/JetBrains/compose-multiplatform/pull/5356)
m
A pull request might speed up the fix 😉.
s
yeah about that.. I'm having some trouble setting up the repo locally. how do I import the project when IJ refuses to show the gradle window or any project files
🤷‍♂️ 1
r
This obviously shouldn't be your default, but you could just "free-hand" the PR edit in something like vim, notepad, nano, vs code, etc. Should be ok as long as you know what the issue is, what should fix it, and code reviewers / PR checks do their part
s
that's what I did now and it's just two lines (hopefully)
👍 2
a
I’ll get it in this week.
s
oh that would be great! thank you
a
I answered in detail in the PR, but at first glance it doesn’t seem like quoting is needed. Maybe it’s the
ö
character that is causing the problem?
s
Thing is that when I try the commands in my terminal manually it does not work without quotes, but works with quotes. I also added some manual signing tasks in gradle where passing the ö to the cli worked fine
a
What is the command that works, though?
It looks like the command in your manual task is
productsign
. But in the PR you are changing the arguments to the
security
command.
s
Yep but I'd assume if ö works in productsign it also works in security. Manual command i tried was the find-certificate from security
Not logged in to gh on phone but regarding 1) I also don't see why it would work. The gradle log showed the command without quotes and that way ID and path arguments could never be distinguishable
regarding 2) could you try only putting "Developer ID Application: Compose Test" in quotes and leaving the keychain path without quotes? I think I made a mistake here, all find-certificate uses I find online put dev ID in quotes but not the keychain path (which doesn't need to be a path either it seems, just 'login.keychain' would be enough too)
a
I just created a new keychain with a certificate where the developer id is
Developer ID Application: Compose Test Sö
and I get the same thing.
security
works without quotes; doesn’t work with quotes.
🫤 1
So the problem is elsewhere.
s
I don't think it's necessarily the ö, I think the name matching just doesn't work. https://ss64.com/mac/security-find-cert.html actually matches on the name so only
find-certificate -c Dominik
works too (tried in terminal it works). However,
find-certificate -c 3rd Party Mac Developer Application: Dominik
does not work while
find-certificate -c "3rd Party Mac Developer Application: Dominik"
works
a
Can you create a cert with the “Developer ID Application: ” prefix and try that?
s
same
a
No, don’t run it at the command line. Run the task from our gradle plugin
You’re assuming that the command you see in the gradle log is the raw string being executed. It’s not.
That’s why adding quotes there actually breaks it.
s
I see, my bad then. I can see in debug logs that it lists the certificate but still fails with " could not find certificate"
a
Can you post the exact output of that part?
s
Copy code
2025-07-06T15:01:48.748+0200 [INFO] [org.gradle.process.internal.DefaultExecHandle] Starting process 'command '/usr/bin/security''. Working directory: /Users/domin/IdeaProjects/ClubManager/composeApp Command: /usr/bin/security find-certificate -a -c Developer ID Application: Dominik
2025-07-06T15:01:48.748+0200 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Changing state to: STARTING
2025-07-06T15:01:48.748+0200 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Waiting until process started: command '/usr/bin/security'.
2025-07-06T15:01:48.755+0200 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Changing state to: STARTED
2025-07-06T15:01:48.755+0200 [DEBUG] [org.gradle.process.internal.ExecHandleRunner] waiting until streams are handled...
2025-07-06T15:01:48.755+0200 [INFO] [org.gradle.process.internal.DefaultExecHandle] Successfully started process 'command '/usr/bin/security''
2025-07-06T15:01:48.768+0200 [QUIET] [system.out] keychain: "/Users/domin/Library/Keychains/login.keychain-db"
2025-07-06T15:01:48.768+0200 [QUIET] [system.out] version: 512
2025-07-06T15:01:48.768+0200 [QUIET] [system.out] class: 0x80001000 
2025-07-06T15:01:48.768+0200 [QUIET] [system.out] attributes:
2025-07-06T15:01:48.768+0200 [QUIET] [system.out]     "alis"<blob>=0x446576656C6F706572204944204170706C69636174696F6E3A20444F4D494E494B205354C39642592028423941464E483235325129  "Developer ID Application: DOMINIK ST\303\226BY (B9AFNH252Q)"
2025-07-06T15:01:48.768+0200 [QUIET] [system.out]     "cenc"<uint32>=0x00000003 
2025-07-06T15:01:48.768+0200 [QUIET] [system.out]     "ctyp"<uint32>=0x00000001 
2025-07-06T15:01:48.768+0200 [QUIET] [system.out]     
[...]
2025-07-06T15:01:48.773+0200 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] 
2025-07-06T15:01:48.773+0200 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] FAILURE: Build failed with an exception.
2025-07-06T15:01:48.773+0200 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] 
2025-07-06T15:01:48.773+0200 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] * What went wrong:
2025-07-06T15:01:48.773+0200 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] Execution failed for task ':composeApp:createDistributable'.
2025-07-06T15:01:48.773+0200 [ERROR] [org.gradle.internal.buildevents.BuildExceptionReporter] > Could not find certificate for 'Developer ID Application: Dominik' in keychain []
let me know if you need more in between, I can send it as a file
a
The certificate is matched via
Copy code
Pattern.compile("\"alis\"<blob>=\"([^\"]+)\"")
For you, the output is
Copy code
"alis"<blob>=0x446576656C6F706572204944204170706C69636174696F6E3A20444F4D494E494B205354C39642592028423941464E483235325129  "Developer ID Application: DOMINIK ST\303\226BY (B9AFNH252Q)"
So it doesn’t match because of the long hexadecimal string
I don’t know what it’s for
or whether it’s normal for it to be there
s
it's the encoded id
I'd assume that's because of the ö then
a
Is it supposed to be there? It doesn’t appear in the test project. The ö seems to be encoded via
T\303\226BY
, although I have no idea what this encoding is.
a
We can add
[^\"]*
to the regex after
=
s
I don't know much about the certificates but those are all the official ones I requested from apple
a
So it’s ö in octal
s
let's see if it's easy enough to change my legal name of the dev account 😅
a
The problem, at this stage, is not in the JDK. It’s just that the JDK has (had) a similar problem.
That regex is in our (Compose gradle plugin) code.
We probably copied it from the JDK, or both we and the JDK copied it from a common source.
s
ah I thought it's depending on jpackage
a
It does
but it also runs
security find-certificate
itself
and parses the output
s
Got it. Well, should have investigated further initially, assumed it's a trivial fix sorry
a
I fixed it, but you will need to use JDK 21 or later because jpackage in versions before that has the same issue.
s
Yeah won't be a problem. thank you!