# Local build configuration. Copy to `.env` (gitignored) and fill in. # # cp .env.example .env # # build.sh reads `.env` automatically if it exists. Anything already set in # the environment wins over this file, so a one-off # # SHANNONCOAT_SIGN_IDENTITY= ./build.sh # # still forces an ad-hoc build without editing anything. # --------------------------------------------------------------------------- # Code-signing identity # --------------------------------------------------------------------------- # The common name of the code-signing certificate in your keychain. Not a # secret — it's a label, not a credential — but it lives here so every build # picks it up without you having to remember the variable. # # Why bother signing at all: macOS pins an *ad-hoc* signed app's # Accessibility grant to its exact cdhash, which changes on every build. So # an unsigned local build silently loses the permission each time you # rebuild and reinstall, while still appearing listed and ticked under # Privacy & Security → Accessibility. Signing with a certificate gives the # app a stable designated requirement, and the grant survives. # # Leave empty (or delete the line) to build ad-hoc. SHANNONCOAT_SIGN_IDENTITY="shannoncoat Signing" # --------------------------------------------------------------------------- # Certificate material — only needed to publish the GitHub Actions secrets # --------------------------------------------------------------------------- # The build itself never reads these: once the certificate is imported, the # private key lives in your keychain and codesign finds it by the identity # name above. They're recorded here purely so the `gh secret set` commands # at the bottom have somewhere to read from. # # Keep the .p12 OUTSIDE the working tree. A gitignored file is still one # `git add -f`, one editor-indexed backup, or one shared folder away from # leaking, and this one holds a private key. # # The $HOME below is expanded by the shell when you `source .env` (which is # how the gh commands at the bottom read it). build.sh parses rather than # sources this file, so it takes values literally — which costs nothing # here, as the only variable it actually reads is the identity above. SHANNONCOAT_P12_PATH="$HOME/.shannoncoat-signing/shannoncoat-signing.p12" # The .p12 export password. Storing it in plaintext here is weaker than # leaving it in your password manager and typing it when prompted — prefer # leaving this field empty and letting `gh secret set` ask for it # interactively. # # Leaving the *field* empty is fine. Exporting the .p12 itself with an # empty password is not: macOS cannot import one, so CI would fail even # though local builds carry on working (they import the PEM pair, which # needs no password). Give the export a real password. SHANNONCOAT_P12_PASSWORD="" # --------------------------------------------------------------------------- # One-time setup # --------------------------------------------------------------------------- # Generate a ten-year self-signed code-signing certificate (codesign refuses # an expired one, and replacing it later resets every user's Accessibility # permission again): # # mkdir -p ~/.shannoncoat-signing && chmod 700 ~/.shannoncoat-signing # openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \ # -keyout ~/.shannoncoat-signing/key.pem \ # -out ~/.shannoncoat-signing/cert.pem \ # -subj "/CN=shannoncoat Signing" \ # -addext "basicConstraints=critical,CA:false" \ # -addext "keyUsage=critical,digitalSignature" \ # -addext "extendedKeyUsage=critical,codeSigning" # # Bundle it as a .p12. `-legacy` is required: OpenSSL 3's default encoding # is one macOS cannot read, and `security import` then fails with a # misleading "MAC verification failed (wrong password?)". # # openssl pkcs12 -export -legacy \ # -inkey ~/.shannoncoat-signing/key.pem \ # -in ~/.shannoncoat-signing/cert.pem \ # -name "shannoncoat Signing" \ # -out ~/.shannoncoat-signing/shannoncoat-signing.p12 # # Import for local builds, then delete the now-redundant loose private key # (the .p12 remains your only backup, so keep that): # # security import ~/.shannoncoat-signing/shannoncoat-signing.p12 \ # -k ~/Library/Keychains/login.keychain-db -T /usr/bin/codesign # rm ~/.shannoncoat-signing/key.pem # # The first signed build raises a "codesign wants to use key…" dialog — # choose Always Allow. Then re-grant Accessibility one final time; from # then on it persists across rebuilds. # # Note that `security find-identity -v -p codesigning` will report "0 valid # identities": -v filters to *trusted* certificates and a self-signed one # reads as CSSMERR_TP_NOT_TRUSTED. codesign uses it regardless. Drop the -v # to see it. # --------------------------------------------------------------------------- # Publishing the same certificate to GitHub Actions # --------------------------------------------------------------------------- # Releases need this too — an ad-hoc release revokes the Accessibility # permission of everyone who updates. .github/workflows/release.yml stays # inert until all three secrets exist, so nothing breaks in the meantime. # # source .env # base64 -i "$SHANNONCOAT_P12_PATH" | gh secret set SIGNING_CERTIFICATE_P12 # gh secret set SIGNING_IDENTITY --body "$SHANNONCOAT_SIGN_IDENTITY" # gh secret set SIGNING_CERTIFICATE_PASSWORD # prompts, so it stays out of shell history # # This buys permission persistence, not Gatekeeper approval: a self-signed # certificate isn't notarized, so downloads are still blocked on first open # and need System Settings → Privacy & Security → Open Anyway.