Code signing (macOS)¶
How to sign the dashboard binaries. The build supports two modes:
- Ad-hoc (default) — every binary is signed with the system's ad-hoc signature. Works for CI, scripting, offline use, and for the Touch ID credential gate (which uses LAContext and needs no entitlement). This is the no-config path and what you want for personal development.
- Developer ID — every binary is signed with your Apple Developer ID Application certificate. Required for redistribution (Gatekeeper acceptance, notarization).
The Touch ID credential gate works on any signing configuration, including ad-hoc. You only need Developer ID signing if you plan to share the binary with other Macs.
The rest of this doc covers the Developer ID path.
Quick start¶
# 1. Find your identity. Look for "Developer ID Application".
security find-identity -v -p codesigning
# 2. Configure with the identity + team ID.
cmake --preset=release \
-DQE_CODESIGN_IDENTITY="Developer ID Application: Your Name (XXXXXXXXXX)" \
-DQE_CODESIGN_TEAM_ID=XXXXXXXXXX
# 3. Build. Every binary and the .app bundle get signed.
cmake --build --preset=release -j
# 4. Verify.
codesign -dv --entitlements - build/release/bin/qe_tests
# Expected: "keychain-access-groups" array containing your team
# ID + "com.jiucheng.quant-engine".
Which identity do I need?¶
security find-identity -v -p codesigning can show several
identity types. Only one works for redistribution without extra
setup:
| Identity prefix | Use case |
|---|---|
Developer ID Application: … |
What you want. Local builds plus distribution to other Macs. |
Apple Development: … |
iOS sideload + Mac testing through Xcode-managed profiles. Killed by AMFI (-413 No matching profile found) when launched without an embedded provisioning profile. |
Mac Developer: … |
Legacy. Same problem as Apple Development. |
3rd Party Mac Developer Application: … |
Mac App Store only — different sandbox model than this project uses. |
If you only have an Apple Development cert and try to use it,
the build succeeds but every signed binary crashes at launch
with SIGKILL because AMFI refuses to honor the entitlement
without a matching provisioning profile. This is Apple policy,
not a build-system bug — the codesign step ran correctly and
the entitlement is embedded; AMFI rejects the entitlement claim
at process start.
Getting a Developer ID Application cert¶
If you have an Apple Developer Program membership but no
Developer ID Application cert yet:
- Go to https://developer.apple.com/account/resources/certificates/list.
- Click
+→ Developer ID Application (not Apple Development). - Generate a CSR: Keychain Access → Certificate Assistant → "Request a Certificate from a Certificate Authority…", saved to disk.
- Upload the CSR, download the
.cerfile, double-click to install into your login keychain. - Confirm:
security find-identity -v -p codesigningshould now list aDeveloper ID Application: …row.
The 10-character code in parentheses at the end of the identity
string is your Team ID. Use it for QE_CODESIGN_TEAM_ID.
What the entitlement does¶
build/release/qe_entitlements.plist (generated from
cmake/qe_entitlements.plist.in) claims one entitlement:
<key>keychain-access-groups</key>
<array>
<string>XXXXXXXXXX.com.jiucheng.quant-engine</string>
</array>
This tells the OS keychain that binaries claiming
com.jiucheng.quant-engine (under your team ID) are allowed to
share keychain items in a single trust group. The dashboard
doesn't need this for the default Touch ID gate (which uses
LAContext instead), but it lets us turn on a future
OS-enforced ACL gate that would survive a debugger attached to
the dashboard process.
We deliberately do NOT claim:
com.apple.security.app-sandbox— would block reads under~/Documents/quant-strategyand other user folders the dashboard actually wants to reach.com.apple.security.cs.allow-jit— we don't JIT anything.com.apple.security.cs.disable-library-validation— we statically link via vcpkg; no untrusted dylib loading needed.
Notarization¶
Notarization is the step that lets a signed .app launch on
another Mac without Gatekeeper warnings. The signing pipeline
stops at signing; notarization is a release-time step that
requires an Apple-ID-paired keychain credential (xcrun
notarytool store-credentials) and a round trip to Apple's
notarization service.
A future release will add scripts/notarize.sh and wire it into
the release workflow. For now, a signed binary works fine on
your own machine; for distribution you'll want to notarize
manually before shipping.
Troubleshooting¶
Failed to parse entitlements: AMFIUnserializeXML: syntax error¶
The entitlements plist must not contain XML comments
(<!-- ... -->). The CMake template is comment-free for this
reason. If you copy a plist from somewhere else and add
comments, codesign will reject it with this error.
codesign failed: -1 / errSecInternalError¶
Usually your identity has expired or been revoked. Re-check with
security find-identity -v -p codesigning.
errSecMissingEntitlement (-34018) at runtime¶
You're running an ad-hoc-signed binary (QE_CODESIGN_IDENTITY
empty) while some code path expects the keychain-access-groups
entitlement. Either set QE_NO_LAUNCH_LOCK=1 to bypass for that
session, or rebuild with QE_CODESIGN_IDENTITY=....
Disallowing <name> because no eligible provisioning profiles found¶
You're using an Apple Development identity instead of a
Developer ID Application identity. See the identity table
above; the fix is to get a Developer ID Application cert from
developer.apple.com.
See also¶
- credentials-security.md — what the launch gate protects, recovery paths, env-var bypass.
cmake/QeCodesign.cmake— the helper module exposingqe_codesign()andqe_codesign_bundle().cmake/qe_entitlements.plist.in— the entitlement template.