Skip to content

macOS code signing, notarization & DMG distribution #13

@yankay

Description

@yankay

Summary

Set up macOS code signing, notarization, and DMG packaging for ClawWork so that users can download and open the app without Gatekeeper warnings.

Background

macOS Gatekeeper blocks unsigned apps. Without code signing + notarization, users must manually bypass security prompts (xattr -cr), which is a poor first-run experience and hurts adoption.

Proposed Approach

1. Apple Developer Certificate

  • Obtain an Apple Developer ID Application certificate ($99/year)
  • Export as .p12 and store in GitHub Secrets:
    • CSC_LINK — base64-encoded .p12 file
    • CSC_KEY_PASSWORD — certificate password
    • APPLE_ID — Apple ID email
    • APPLE_APP_SPECIFIC_PASSWORD — app-specific password for notarization
    • APPLE_TEAM_ID — Apple Developer Team ID

2. electron-builder Configuration

Update packages/desktop/electron-builder.yml (or package.json build config):

mac:
  category: public.app-category.developer-tools
  target:
    - target: dmg
      arch: [universal]
  identity: "Developer ID Application: <Team Name> (<Team ID>)"
  hardenedRuntime: true
  gatekeeperAssess: false
  entitlements: build/entitlements.mac.plist
  entitlementsInherit: build/entitlements.mac.plist

afterSign: scripts/notarize.js

dmg:
  sign: true
  contents:
    - x: 130
      y: 220
    - x: 410
      y: 220
      type: link
      path: /Applications

3. Notarize Script

Create scripts/notarize.js using @electron/notarize:

const { notarize } = require('@electron/notarize');

exports.default = async function notarizing(context) {
  const { electronPlatformName, appOutDir } = context;
  if (electronPlatformName !== 'darwin') return;

  const appName = context.packager.appInfo.productFilename;
  await notarize({
    appBundleId: 'com.clawwork.desktop',
    appPath: `${appOutDir}/${appName}.app`,
    appleId: process.env.APPLE_ID,
    appleIdPassword: process.env.APPLE_APP_SPECIFIC_PASSWORD,
    teamId: process.env.APPLE_TEAM_ID,
  });
};

4. GitHub Actions Integration

Add signing steps to CI (depends on #7):

- name: Build & Sign (macOS)
  if: matrix.os == 'macos-latest'
  env:
    CSC_LINK: ${{ secrets.CSC_LINK }}
    CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
    APPLE_ID: ${{ secrets.APPLE_ID }}
    APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
    APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
  run: pnpm --filter @clawwork/desktop build

5. Unsigned Dev Builds (Fallback)

For contributors and development builds without certificates:

mac:
  identity: null  # skip signing

README should document:

# If you get "app is damaged" or Gatekeeper warning:
xattr -cr /Applications/ClawWork.app

Tasks

  • Obtain Apple Developer ID certificate
  • Create build/entitlements.mac.plist with hardened runtime entitlements
  • Create scripts/notarize.js
  • Add electron-builder mac config
  • Add signing secrets to GitHub repo
  • Integrate into CI pipeline (blocked by CI: Add basic GitHub Actions CI pipeline #7)
  • Test: download DMG from GitHub Release → double-click install → no Gatekeeper warning
  • Document unsigned build workaround in README

References

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions