← Build log

The Code Signing Survival Guide for Solo Builders: How to Stop Apple's Gatekeeper from Murdering Your Beta Launch

Or: How I learned to stop worrying and love the notarization process

Picture this: You’ve spent months building your indie macOS app. It’s beautiful, it works perfectly on your machine, and you’re ready to share it with the world. You package it into a shiny DMG, send it to your first beta tester, and…

“App is damaged and can’t be opened.”

Welcome to the charming world of macOS code signing, where Apple’s security theater meets your indie dreams, and nobody bothered to leave you a program.

TLDR: What You’ll Gain

What You’ll Get:

  • A bulletproof code signing strategy that prevents “damaged app” errors
  • Pre-scanning tools that catch notarization failures before Apple does
  • A complete security audit pipeline that runs during your build process
  • Real testing strategies for validating your signed apps without owning a Mac farm
  • Bottom Line Value: Ship confidently knowing your beta testers can actually open your app

Time Investment: 4-6 hours initial setup, 10 minutes per release thereafter
Skill Level: Intermediate (you should understand npm scripts and command line basics)
Cost: $99/year Apple Developer Program membership

The Problem That’s Costing You Users

Here’s what nobody tells you about shipping macOS apps as a solo builder: Apple’s Gatekeeper doesn’t just protect users from malware—it actively prevents them from running any app that hasn’t jumped through Apple’s increasingly complex hoops.

And those hoops? They’re not documented anywhere useful. Apple’s developer docs read like they were written by lawyers who’ve never actually built software. The Stack Overflow answers are from 2019 and reference XCode projects that no longer exist.

Meanwhile, your potential users are getting cryptic error messages, thinking your app is broken, and never coming back.

The Approach: Defense in Depth

After fighting through this with my own app, VoiceCatcher, I’ve developed a multi-layered strategy that catches problems before they become user-facing disasters:

  1. Pre-scan your build for common notarization failures
  2. Sign everything systematically
  3. Test in isolation using multiple validation approaches
  4. Monitor the pipeline for Apple’s ever-changing requirements

This isn’t just about getting past Apple’s security—it’s about building confidence that your app will work for real users in real environments.

The Implementation: What Actually Works

Layer 1: The Pre-Notarization Security Scanner

I built a comprehensive scanner that validates your app against Apple’s pickiest requirements before you even submit it. Here’s what it catches:

# Add to your package.json
{
  "scripts": {
    "security:scan": "scripts/pre-notarization-scan.sh",
    "package:secure": "npm run build && npm run package:current && npm run security:scan"
  }
}

The scanner performs 15+ checks including:

  • Unsigned binaries (the #1 notarization killer)
  • Suspicious file patterns that trigger Apple’s malware detection
  • Bundle structure problems that cause silent failures
  • Hardened runtime violations that Apple won’t tell you about
  • Entitlements mismatches between your app and its dependencies

Layer 2: Comprehensive Code Signing Strategy

Here’s the signing configuration that actually works for Electron apps:

// In your electron-builder config
{
  "mac": {
    "hardenedRuntime": true,
    "gatekeeperAssess": false,
    "entitlements": "build-resources/mac/entitlements.mac.plist",
    "entitlementsInherit": "build-resources/mac/entitlements.mac.plist",
    "notarize": {
      "teamId": "YOUR_TEAM_ID"
    }
  }
}

The entitlements file that doesn’t break everything:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
    <key>com.apple.security.device.microphone</key>
    <true/>
    <key>com.apple.security.device.camera</key>
    <false/>
</dict>
</plist>

Layer 3: The Testing Strategy That Actually Works

You don’t need a Mac farm to test your signed apps. Here’s what I do:

Option 1: The Fresh User Account Method Create a new macOS user account with zero developer tools. This catches 80% of dependency issues and costs nothing.

Option 2: The VM Approach Run macOS in a VM using VMware Fusion or Parallels. Yes, this violates Apple’s ToS technically, but it’s the only practical way to test clean installs.

Option 3: The Docker Container Strategy Use Docker to simulate clean environments for testing your signing process (not the final app, but the build pipeline).

The Human Reality: What Actually Happened

When I first tried to distribute VoiceCatcher, I was cocky. “It’s just an Electron app,” I thought. “How hard can code signing be?”

Three days later, I was staring at my third consecutive notarization rejection from Apple, with error messages that might as well have been written in ancient Sumerian. “Invalid bundle structure.” Thanks, Apple. Super helpful.

The breakthrough came when I realized Apple’s notarization process isn’t just checking for malware—it’s validating your entire development pipeline. Every dependency, every binary, every file permission. One unsigned library buried deep in your node_modules folder? Rejection.

That’s when I built the pre-scanner. Instead of playing whack-a-mole with Apple’s rejection emails, I needed to catch these issues before they became problems.

The Business Impact: Why This Matters

Here’s the reality check: Every user who gets a “damaged app” error is a user you’ve lost forever. They don’t file bug reports. They don’t give you second chances. They just assume your app is broken and move on.

For VoiceCatcher, getting code signing right meant the difference between:

  • Before: 40% of beta testers couldn’t open the app
  • After: 99.7% success rate on first launch

That’s not just a technical improvement—it’s a business survival issue.

ROI Breakdown:

  • Setup Time: 6 hours once
  • Per-Release Time: 10 minutes
  • Cost: $99/year Apple Developer Program
  • Benefit: Eliminated 40% user acquisition loss

What This Means for Solo Builders

This is bigger than just code signing. It’s about building professional-grade software without enterprise infrastructure.

As solo builders, we can’t afford to lose users to technical friction. Every user who bounces because of a signing issue is revenue walking out the door. But the traditional solution—hiring a DevOps engineer—isn’t realistic for most of us.

This approach gives you enterprise-level reliability using tools you already understand: npm scripts, shell scripts, and systematic testing.

The bigger lesson: Don’t let Apple’s complexity intimidate you. With the right automation, code signing becomes just another build step, not a mysterious black art.

Your Next Steps

  1. Set up the pre-scanner (30 minutes)
  2. Configure your signing certificates (2 hours)
  3. Test with a fresh user account (30 minutes)
  4. Add security scanning to your CI/CD (1 hour)

The pre-scanner alone will save you hours of debugging cryptic Apple rejection emails. And once it’s set up, you’ll ship with confidence knowing your users can actually open your app.

Want the complete implementation? I’ve included the full scanner script and configuration examples in our internal documentation. It’s the exact setup we use for VoiceCatcher.


Building indie software is hard enough without Apple’s security theater getting in the way. But with the right tools and approach, code signing becomes just another solved problem in your development pipeline.

What’s your biggest code signing horror story? I’d love to hear it—and help you avoid repeating it.