Overview

Code Signing

The identity is the same on every CI release, so users can verify what they downloaded:

codesign -dv --verbose=4 Justty.app
# expect Authority=Justty Self-Signed
codesign --verify --verbose=4 Justty.app

Self-signing does not satisfy Gatekeeper for downloads, which is why first launch needs the steps in First Launch.

Maintainers: create the identity#

You create it once, then export it into two GitHub secrets the release workflow imports.

The quick path from the repo root:

./Script/setup-signing.sh

That creates the identity if it is missing and prints the gh secret set commands, or runs them when gh is already authed for the repo.

Manual creation#

openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \
  -keyout /tmp/justty-key.pem -out /tmp/justty-cert.pem \
  -subj "/CN=Justty Self-Signed" \
  -addext "basicConstraints=critical,CA:false" \
  -addext "keyUsage=critical,digitalSignature" \
  -addext "extendedKeyUsage=critical,codeSigning"
 
# OpenSSL 3 defaults break macOS `security import` — use classic PBE.
openssl pkcs12 -export -inkey /tmp/justty-key.pem -in /tmp/justty-cert.pem \
  -name "Justty Self-Signed" -out /tmp/justty.p12 -passout pass:justty \
  -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg sha1
 
security import /tmp/justty.p12 -k ~/Library/Keychains/login.keychain-db \
  -P justty -A -T /usr/bin/codesign
 
rm -f /tmp/justty-key.pem /tmp/justty-cert.pem /tmp/justty.p12

Verify it landed:

security find-identity -p codesigning | grep "Justty Self-Signed"

Maintainers: CI secrets#

P12_PASSWORD="$(openssl rand -hex 24)"; echo "password: $P12_PASSWORD"
 
security export -t identities -f pkcs12 \
  -k ~/Library/Keychains/login.keychain-db \
  -P "$P12_PASSWORD" -o /tmp/signing.p12
base64 -i /tmp/signing.p12 | tr -d '\n' > /tmp/signing.p12.base64
rm -f /tmp/signing.p12
 
gh secret set SIGNING_P12_BASE64 < /tmp/signing.p12.base64
gh secret set SIGNING_P12_PASSWORD --body "$P12_PASSWORD"
rm -f /tmp/signing.p12.base64

Lost the secrets but still have the identity in your keychain? Re-export using the block above. Lost the identity entirely? Recreate it and redo the secrets. The Authority string stays Justty Self-Signed, but it is a new key.

Updated