mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-11 16:57:39 +00:00
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 <identity>`, 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: <TEAMID>" -> 0 matches
find-certificate -c "Developer ID Application: <full CN>" -> 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) <noreply@anthropic.com>
91 lines
4.6 KiB
YAML
91 lines
4.6 KiB
YAML
name: Import macOS Developer ID certificate
|
|
description: >
|
|
Import a Developer ID Application certificate (base64-encoded .p12) into a
|
|
throwaway keychain so codesign/jpackage can find it during the job. Soft:
|
|
when no certificate is supplied it is a no-op and reports signing=false, so
|
|
callers build UNSIGNED artifacts exactly as before.
|
|
|
|
inputs:
|
|
certificate-p12-base64:
|
|
description: Base64 of the Developer ID Application .p12 (cert + private key)
|
|
required: true
|
|
certificate-password:
|
|
description: Password used when the .p12 was exported
|
|
required: true
|
|
|
|
outputs:
|
|
signing:
|
|
description: "'true' if a certificate was imported, else 'false'"
|
|
value: ${{ steps.import.outputs.signing }}
|
|
keychain:
|
|
description: >
|
|
Absolute path of the throwaway keychain holding the imported cert (empty
|
|
when signing=false). Pass to tools that need an explicit keychain — e.g.
|
|
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 <identity>`
|
|
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
|
|
steps:
|
|
- id: import
|
|
shell: bash
|
|
env:
|
|
CERT_P12: ${{ inputs.certificate-p12-base64 }}
|
|
CERT_PASSWORD: ${{ inputs.certificate-password }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ -z "${CERT_P12:-}" ]]; then
|
|
echo "::notice::No macOS signing certificate configured — artifacts will be UNSIGNED."
|
|
echo "signing=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
KEYCHAIN="$RUNNER_TEMP/amethyst-signing.keychain-db"
|
|
KEYCHAIN_PWD="$(openssl rand -base64 24)"
|
|
CERT_PATH="$RUNNER_TEMP/developer_id.p12"
|
|
security create-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN"
|
|
security set-keychain-settings -lut 21600 "$KEYCHAIN"
|
|
security unlock-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN"
|
|
echo "$CERT_P12" | base64 --decode > "$CERT_PATH"
|
|
security import "$CERT_PATH" -P "$CERT_PASSWORD" \
|
|
-k "$KEYCHAIN" -T /usr/bin/codesign -T /usr/bin/productsign
|
|
# Let codesign use the private key without an interactive UI prompt.
|
|
security set-key-partition-list -S apple-tool:,apple:,codesign: \
|
|
-s -k "$KEYCHAIN_PWD" "$KEYCHAIN" >/dev/null
|
|
# Prepend our keychain to the user search list so codesign sees it.
|
|
security list-keychains -d user -s "$KEYCHAIN" \
|
|
$(security list-keychains -d user | sed -e 's/[\"[:space:]]//g')
|
|
# Also make it the default keychain. Bare `codesign` resolves identities
|
|
# via the search list, but some tools (Compose's MacSigner runs
|
|
# `security find-certificate` to map the identity to a cert) don't find
|
|
# it on the search list alone on these runners. Callers that need an
|
|
# 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 <name>` (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
|