Define the security boundary
Enable Hardened Runtime
Adopt runtime protections for distributed code and grant exceptions only for behavior the application can justify and test.
The Hardened Runtime is a set of protections your app opts into at signing time. It blocks code injection, loading of unsigned or tampered libraries, and debugger attachment in shipped builds. You’re telling macOS: this process should never be modified at runtime — enforce that.
You need it. Notarization requires the Hardened Runtime on every executable in a Developer ID distribution. No hardened runtime, no notarization, no smooth installs.
In Xcode, add the Hardened Runtime capability under Signing & Capabilities for the app target and every helper or bundled tool target. If you sign manually in a script, it’s the --options runtime flag:
codesign --force --options runtime \
--sign "Developer ID Application: Flavio Copes (ABCDE12345)" \
Notes.app
Verify it took. The flags line must include runtime:
codesign -d --verbose=2 Notes.app
Look for flags=0x10000(runtime) in the output.
The runtime has escape hatches: exceptions for just-in-time compilation, unsigned executable memory, debugging, and library validation. Some apps genuinely need one — an app embedding a JavaScript engine with JIT, for example. But every exception switches off one specific protection, so treat them like sandbox entitlements: none by default, each one justified by a feature you can name.
When a third-party dependency crashes under the hardened runtime, investigate before reaching for an exception. Often the real problem is a badly signed framework, and the right fix is re-signing or updating the dependency, not disabling library validation for your whole app.
And check that debug entitlements are gone. com.apple.security.get-task-allow must not survive into a shipping build.
The failure you’ll actually meet: a scripted build that signs without --options runtime. Everything works locally. Then notarytool returns Invalid, and the log says the executable does not have the hardened runtime enabled. Recognize that message, add the flag, re-sign, resubmit.
Lesson completed