The Application Model: App Bundles, Code Signing & Gatekeeper

macOS

Chapter 6 · The Application Model: App Bundles, Code Signing & Gatekeeper

Chapter 5 covered how software actually gets installed. This chapter answers a different question: once it's on disk, what actually is a macOS application, and what decides whether the system trusts it enough to run? The answer is three separate mechanisms — a packaging format, a cryptographic identity check, and an automated malware scan — all enforced at one single moment: the first time you try to open something.

.app Bundles: Applications Are Actually Folders

A macOS .app is not one file the way a Windows .exe typically is — it's a directory that Finder displays and treats as if it were a single double-clickable icon, called a bundle. Right-click any app and choose "Show Package Contents" to see the real structure underneath.

ls /Applications/Safari.app/Contents/ # Info.plist MacOS/ Resources/ _CodeSignature/ ... cat /Applications/Safari.app/Contents/Info.plist # raw XML plutil -p /Applications/Safari.app/Contents/Info.plist # human-readable
  • Contents/MacOS/ — the actual executable binary Finder launches when you double-click the bundle.
  • Contents/Resources/ — icons, images, and localized strings the app needs at runtime.
  • Contents/Info.plist — an XML metadata file: the app's bundle identifier, version number, minimum supported macOS version, and which icon file to show, among other things.

Windows 11 Fundamentals 6 covered MSIX as Windows 11's own move toward self-contained, sandboxed app packaging, contrasted there against older loose EXE/MSI installers whose files often end up scattered across Program Files subfolders. A .app bundle is conceptually much closer to MSIX's own self-contained philosophy than to a classic loose EXE — everything the app needs, in one predictable folder structure, even though the two use completely different underlying packaging technology.

Code Signing: Proving Who Built It

A legitimate macOS app is code-signed with a Developer ID certificate Apple issues to a registered developer. Cryptography Fundamentals already covered the general mechanism this relies on — asymmetric-key digital signatures — and code signing is that exact idea, applied directly: the developer signs the binary with their own private key, and macOS verifies the signature against a certificate chain rooted in Apple's own certificate authority. A valid signature proves two separate things at once: the binary hasn't been altered since it was signed, and which developer or organization actually signed it.

codesign -dv --verbose=4 /Applications/Safari.app # shows the signing identity, certificate chain, and signature validity

Notarization: A Second, Apple-Side Check

Signing alone only proves identity and integrity — it says nothing about whether the app is actually malicious. Since macOS Catalina (2019, the same release that switched the default shell to zsh in Chapter 4), Apple requires apps distributed outside the Mac App Store to also be notarized: the developer uploads the already-signed app to an automated Apple scanning service, which checks it against known-malware signatures and basic policy rules, then returns a ticket that gets attached (stapled) to the app. This is a genuinely separate step from signing — signing is something the developer does with their own key; notarization is something Apple's own servers do afterward, automatically, with no human reviewer involved.

Gatekeeper: Enforcing It All at Launch Time

Gatekeeper is the piece that actually checks all of this, the first time you open a downloaded app. It looks for a valid signature and a valid notarization ticket, and by default blocks anything missing either one, showing a dialog to that effect rather than launching it silently. This produces a real three-tier trust model:

Distribution channelChecks appliedDefault Gatekeeper behavior
Mac App StoreFull human review, plus mandatory sandboxingAllowed automatically
Signed & notarized, outside the App StoreAutomated malware/policy scan only, no human review, sandboxing not mandatoryAllowed automatically
Unsigned or unnotarizedNoneBlocked by default; requires an explicit user override

Windows 11's rough counterpart is Windows Defender SmartScreen, which likewise warns about unrecognized publishers — but SmartScreen leans more on file-reputation heuristics and can often be bypassed with a "Run anyway" click with no cryptographic signing chain involved at all. Gatekeeper's default posture is more uniformly strict: every unsigned app is blocked the same way, regardless of reputation, unless the user deliberately overrides it.

Three mechanisms, one enforcement point
The bundle format, code signing, and notarization each answer a different question — what is this app made of, who built it, and did Apple's own scan find anything concerning — but none of them do anything by themselves. Gatekeeper is the single choke point where all three checks are actually enforced, at the one moment (first launch) it matters most. Layering several independent checks behind one consistent enforcement point, rather than trusting any single check alone, is the same defense-in-depth thinking that shows up throughout the Security subject.
Checking trust status directly from Terminal
Alongside codesign -dv --verbose=4 from earlier, Gatekeeper has its own dedicated command-line tool: spctl -a -vv /path/to/App.app reports exactly what Gatekeeper itself would decide, without actually launching the app — useful for checking a downloaded app's status before double-clicking it.
A narrow override and a global one are not the same risk
Right-clicking a specific, known-trustworthy-but-unsigned app and choosing Open (or approving it via System Settings > Privacy & Security after a first blocked attempt) is a narrow, deliberate exception for that one app only. Running sudo spctl --master-disable to turn Gatekeeper off globally is a completely different scale of risk — it removes the check for every app on the machine going forward, not just the one you actually meant to allow. The same narrow-scope-over-blanket-override principle Chapter 3 applied to admin accounts applies here just as directly: prefer the smallest override that solves the actual problem in front of you.

Where This Course Is Headed

APFS as the filesystem underneath everything covered so far, the built-in security stack (Gatekeeper's own neighbors — XProtect, FileVault, System Integrity Protection), Time Machine and Recovery, networking and sharing, everyday troubleshooting tools, and a capstone setting up and securing a complete new Mac end to end.

Hands-On Exercises

Exercise 1

Explain what a .app bundle actually is, and name the three items inside Contents/ this chapter specifically calls out. Why does the chapter compare a .app bundle to Windows 11's own MSIX packaging rather than to a classic loose EXE?

📄 View solution
Exercise 2

A colleague says "the app is signed, so Apple must have checked it for malware." Explain why this conflates two genuinely separate things this chapter describes, and who actually performs each one.

📄 View solution
Exercise 3

Explain why this chapter treats right-click → Open on one specific app and running sudo spctl --master-disable as very different levels of risk, even though both are technically "ways to bypass Gatekeeper." What earlier chapter's own principle does this echo?

📄 View solution

Chapter 6 Quick Reference

  • .app bundle — a folder, not a single file; Contents/MacOS (binary), Contents/Resources (assets), Contents/Info.plist (metadata)
  • Code signing — a real-world digital-signature application (Cryptography Fundamentals); proves identity and integrity, done by the developer
  • Notarization — Apple's own automated post-signing malware/policy scan, done by Apple's servers, since Catalina (2019)
  • Gatekeeper — the single enforcement point checking signature + notarization at first launch; three-tier trust model (App Store / signed & notarized / unsigned-blocked)
  • codesign -dv --verbose=4 / spctl -a -vv — check signing and Gatekeeper status directly from Terminal
  • Narrow override vs. global disable — right-click Open (one app) vs. spctl --master-disable (every app) are very different blast radii
  • Next chapter: The File System — APFS