From 61defaa2e9968e293a511e71229cf367152a7296 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 19 Jun 2026 12:54:56 -0400 Subject: [PATCH] fix(ci): resolve the exact Developer ID common name for Compose signing v1.12.4 got the keychain right ("...in keychain [/Users/.../amethyst-signing .keychain-db]") but createReleaseDistributable still failed with "Could not find certificate". Different layer of the same problem: Compose's MacSigner maps its identity to a cert by running `security find-certificate -c `, prepending "Developer ID Application: " when the identity doesn't already start with it. `codesign --sign` (used by the signMacJarNatives task, which succeeds in the same job) instead matches a SHA-1 hash OR any common-name substring. So a MAC_SIGN_IDENTITY secret that is a fingerprint or a team-ID/partial name signs fine with codesign but, once prefixed by Compose, is not a substring of the cert's common name -> zero matches -> failure. Reproduced locally against the real Developer ID cert: find-certificate -c "Developer ID Application: " -> 0 matches find-certificate -c "Developer ID Application: " -> 1 match Fix: import-macos-cert now resolves the certificate's full "Developer ID Application: NAME (TEAMID)" common name from the keychain (via find-identity) and exposes it as an `identity` output. The desktop build feeds that to Compose's signing.identity, falling back to the raw secret if resolution fails. Independent of whatever form the secret takes. The amy CLI leg keeps using bare codesign with the secret directly and is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/actions/import-macos-cert/action.yml | 24 ++++++++++++++++++++ .github/workflows/create-release.yml | 9 ++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/.github/actions/import-macos-cert/action.yml b/.github/actions/import-macos-cert/action.yml index c2808293d2..223d2c317a 100644 --- a/.github/actions/import-macos-cert/action.yml +++ b/.github/actions/import-macos-cert/action.yml @@ -24,6 +24,15 @@ outputs: Compose's macOS signing, whose certificate lookup doesn't resolve the search list reliably on CI runners the way bare `codesign` does. value: ${{ steps.import.outputs.keychain }} + identity: + description: > + The imported certificate's full "Developer ID Application: NAME (TEAMID)" + common name, resolved from the keychain (empty when signing=false or if it + could not be parsed). `codesign` accepts a SHA-1 hash or a CN substring, + but Compose's MacSigner runs `security find-certificate -c ` + after prepending "Developer ID Application: " — so it only works with the + exact common name. Feed this to Compose's `signing.identity`. + value: ${{ steps.import.outputs.identity }} runs: using: composite @@ -62,5 +71,20 @@ runs: # explicit keychain can read the `keychain` output below. security default-keychain -d user -s "$KEYCHAIN" rm -f "$CERT_PATH" + # Resolve the certificate's exact common name. Compose's MacSigner maps + # its identity to a cert via `security find-certificate -c ` (after + # prepending "Developer ID Application: " when absent), so it needs the + # full CN — a SHA-1 hash or partial name in the secret signs fine with + # bare `codesign` but yields "Could not find certificate ...". Pull the + # canonical name straight from the keychain so the caller is independent + # of whatever form the MAC_SIGN_IDENTITY secret takes. + IDENTITY_NAME="$(security find-identity -v -p codesigning "$KEYCHAIN" \ + | grep -o '"Developer ID Application:[^"]*"' | head -1 | tr -d '"' || true)" echo "signing=true" >> "$GITHUB_OUTPUT" echo "keychain=$KEYCHAIN" >> "$GITHUB_OUTPUT" + echo "identity=$IDENTITY_NAME" >> "$GITHUB_OUTPUT" + if [[ -n "$IDENTITY_NAME" ]]; then + echo "::notice::Resolved signing identity: $IDENTITY_NAME" + else + echo "::warning::Could not resolve a 'Developer ID Application' identity from the keychain; callers will fall back to the MAC_SIGN_IDENTITY secret." + fi diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index cc99337105..93e647773e 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -119,8 +119,13 @@ jobs: env: # Empty on non-macOS legs and on the macOS leg when no cert is # configured — the gradle macOS{} block skips signing when the - # identity is blank. - AMETHYST_MAC_SIGN_IDENTITY: ${{ steps.mac_keychain.outputs.signing == 'true' && secrets.MAC_SIGN_IDENTITY || '' }} + # identity is blank. Prefer the full common name resolved from the + # keychain over the raw secret: Compose's signer maps the identity via + # `security find-certificate` and only matches the exact "Developer ID + # Application: …" CN, whereas the secret may be a hash or partial name + # (which bare codesign accepts but Compose does not). Fall back to the + # secret if resolution failed. + AMETHYST_MAC_SIGN_IDENTITY: ${{ steps.mac_keychain.outputs.signing == 'true' && (steps.mac_keychain.outputs.identity || secrets.MAC_SIGN_IDENTITY) || '' }} # Explicit keychain for Compose's MacSigner. Its `security # find-certificate` lookup doesn't resolve the imported cert via the # search list on these runners ("Could not find certificate ... in