Skip to content

Fix macOS notarization failures for production and nightly builds#371

Merged
Power-Maverick merged 4 commits intodevfrom
copilot/fix-macos-notarization-errors
Feb 9, 2026
Merged

Fix macOS notarization failures for production and nightly builds#371
Power-Maverick merged 4 commits intodevfrom
copilot/fix-macos-notarization-errors

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 9, 2026

Description

macOS notarization failing with three critical errors: missing secure timestamps on all binaries (#3087733), certificate/signing validation failures (#3087721), and unsigned third-party frameworks (#3087724). This PR fixes these issues for both production releases and nightly insider builds.

Changes

Build Configuration (buildScripts/electron-builder-mac.json)

  • Set gatekeeperAssess: false - defer validation to Apple notarization service
  • Add signIgnore: [] - ensure all nested frameworks/dylibs are signed

Entitlements (buildScripts/entitlements.mac.plist)

  • Add com.apple.security.cs.allow-dyld-environment-variables - required for Squirrel.framework auto-updater

CI Workflow (.github/workflows/prod-release.yml)

Pre-build verification:

  • Add certificate identity check step (security find-identity) to catch wrong cert type early

Packaging environment:

  • Set CSC_FOR_PULL_REQUEST: true and CSC_IDENTITY_AUTO_DISCOVERY: true - ensure electron-builder discovers Developer ID cert

Post-build verification:

  • Expand code signing verification to check timestamps on all binaries (app, helpers, frameworks, dylibs)
  • Validate nested components individually before notarization submission

CI Workflow (.github/workflows/nightly-release.yml)

Applied identical fixes to nightly build workflow:

Pre-build verification:

  • Add certificate identity check step (security find-identity) to catch wrong cert type early

Packaging environment:

  • Set CSC_FOR_PULL_REQUEST: true and CSC_IDENTITY_AUTO_DISCOVERY: true - ensure electron-builder discovers Developer ID cert

Post-build verification:

  • Expand code signing verification to check timestamps on all binaries (app, helpers, frameworks, dylibs)
  • Validate nested components individually before notarization submission

Testing Notes

When workflow runs, monitor:

  1. Certificate verification shows "Developer ID Application" (not "Mac App Distribution")
  2. Timestamp checks confirm RFC 3161 timestamps on all binaries
  3. Notarization completes without Apple service errors

Both production and nightly builds will benefit from these fixes.


  • Use a meaningful title for the pull request.
  • Follow the guidelines from the CONTRIBUTING.md.
  • Mention the bug or the feature number the PR will be targeting.
  • Test the change in your own code. (Compile and run)
  • Resolve all GH Copilot comments.
Original prompt

Fix macOS Notarization Failures

Problem Summary

The macOS notarization process is failing for v1.1.2 with multiple errors from Apple's notarization service. Analysis of the GitHub Actions failure logs reveals three critical issues that must be addressed together:

Critical Issues Identified

  1. Missing Secure Timestamps (Error #3087733)

    • All binaries are being signed without secure timestamps
    • Apple requires timestamps to verify signature validity even after certificate expiration
    • Affects: main app, helpers, all frameworks, and dylibs
  2. Invalid Certificate or Signing Issues (Error #3087721)

    • Binaries not properly signed with valid Developer ID certificate
    • May indicate certificate type mismatch or signing process issues
  3. Third-party Frameworks Not Properly Signed (Error #3087724)

    • Squirrel.framework, ReactiveObjC.framework, and Mantle.framework failing
    • Electron Framework components (libEGL.dylib, libGLESv2.dylib, libffmpeg.dylib, etc.) not signed correctly
    • Helper apps and chrome_crashpad_handler missing proper signatures

Required Changes

1. Update buildScripts/electron-builder-mac.json

Current configuration has issues. Update to:

{
    "extends": "buildScripts/electron-builder-base.json",
    "forceCodeSigning": true,
    "mac": {
        "target": [
            {
                "target": "zip",
                "arch": ["x64", "arm64"]
            },
            {
                "target": "dmg",
                "arch": ["x64", "arm64"]
            }
        ],
        "category": "public.app-category.developer-tools",
        "icon": "icons/icon.icns",
        "identity": "Developer ID Application",
        "gatekeeperAssess": false,
        "hardenedRuntime": true,
        "entitlements": "./buildScripts/entitlements.mac.plist",
        "entitlementsInherit": "./buildScripts/entitlements.mac.plist",
        "type": "distribution",
        "notarize": false,
        "signIgnore": []
    },
    "dmg": {
        "sign": true
    }
}

Key changes:

  • gatekeeperAssess: false → Let Apple handle this during notarization
  • Add signIgnore: [] → Ensure nothing is skipped during signing

2. Update buildScripts/entitlements.mac.plist

Add missing entitlement for Squirrel framework:

<?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.app-sandbox</key>
        <false/>
        <key>com.apple.security.cs.allow-jit</key>
        <true/>
        <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
        <true/>
        <key>com.apple.security.cs.allow-dyld-environment-variables</key>
        <true/>
        <key>com.apple.security.inherit</key>
        <true/>
        <key>com.apple.security.device.usb</key>
        <true/>
        <key>com.apple.security.network.client</key>
        <true/>
        <key>com.apple.security.network.server</key>
        <true/>
    </dict>
</plist>

Key addition:

  • com.apple.security.cs.allow-dyld-environment-variables → Required for Squirrel auto-updater framework

3. Update .github/workflows/prod-release.yml

Add certificate verification step (after line 171, before "Package application (macOS)"):

            - name: Verify certificate details
              if: matrix.os == 'macos-latest'
              shell: bash
              run: |
                  echo "=== Checking available signing identities ==="
                  security find-identity -v -p codesigning
                  echo ""
                  echo "Note: Should show 'Developer ID Application' not 'Mac App Distribution'"

Update the "Package application (macOS)" step environment variables:

Add these environment variables to ensure proper signing with timestamps:

            - name: Package application (macOS)
              if: matrix.os == 'macos-latest'
              shell: bash
              env:
                  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
                  SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
                  SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }}
                  APPINSIGHTS_CONNECTION_STRING: ${{ secrets.APPINSIGHTS_CONNECTION_STRING }}
                  SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
                  SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
                  SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
                  SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
                  DEBUG: electron-builder
                  CSC_FOR_PULL_REQUEST: true
                  CSC_IDENTITY_AUTO_DISCOVERY: true
              run: |
                  node ./buildScripts/package.js --config=${{ matrix.config }}

Key additions:

  • CSC_FOR_PULL_REQUEST: true → Enables certificate signing in PR context
  • CSC_IDENTITY_AUTO_DISCOVERY: true → Ensures electron...

This pull request was created from Copilot chat.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix macOS notarization failures for v1.1.2 Fix macOS notarization failures: timestamps, certificate discovery, and framework signing Feb 9, 2026
Copilot AI requested a review from Power-Maverick February 9, 2026 12:09
@Power-Maverick
Copy link
Copy Markdown
Contributor

@copilot does this change apply to nightly build

Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 9, 2026

@copilot does this change apply to nightly build

Yes, I've now applied the same fixes to the nightly build workflow (.github/workflows/nightly-release.yml). The changes include:

  1. Added certificate verification step
  2. Added CSC_FOR_PULL_REQUEST and CSC_IDENTITY_AUTO_DISCOVERY environment variables
  3. Enhanced code signing verification with timestamp checks

Both production and nightly builds will now have proper notarization support. Commit: e840196

@Power-Maverick Power-Maverick marked this pull request as ready for review February 9, 2026 12:31
Copilot AI review requested due to automatic review settings February 9, 2026 12:31
Copilot AI changed the title Fix macOS notarization failures: timestamps, certificate discovery, and framework signing Fix macOS notarization failures for production and nightly builds Feb 9, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 9, 2026

Bundle Size Report 📦

Bundle Size
Main Process 4.84 MB
Renderer JS 683.67 KB
Renderer CSS 76.32 KB
Total 5.58 MB

Bundle Analysis Reports

The detailed bundle analysis reports are available in the workflow artifacts:

  • 📊 Main Process: stats-main.html
  • 📊 Renderer Process: stats-renderer.html

Download the artifacts from the workflow run to view interactive visualizations.


Bundle size tracking is now active! This helps prevent bundle bloat.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the macOS signing/notarization configuration and GitHub Actions release workflows to address recurring notarization failures in the Electron build pipeline.

Changes:

  • Adjust macOS electron-builder config to disable Gatekeeper assessment during build and ensure all binaries are signed.
  • Add a macOS entitlement intended to support signing of specific third-party frameworks (Squirrel).
  • Enhance stable and nightly release workflows with certificate visibility checks and expanded pre-notarization signature/timestamp verification.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 9 comments.

File Description
buildScripts/entitlements.mac.plist Adds an entitlement affecting hardened runtime behavior to support framework signing requirements.
buildScripts/electron-builder-mac.json Tweaks macOS signing configuration (Gatekeeper assessment + signing coverage).
.github/workflows/prod-release.yml Adds certificate/verification steps and expands pre-notarization checks for macOS release packaging.
.github/workflows/nightly-release.yml Mirrors the macOS release workflow verification/signing changes for nightly builds.

Comment on lines +232 to +238
# Check dylibs
echo ""
echo "=== Checking dynamic libraries ==="
find "$APP_PATH" -name "*.dylib" -type f | head -5 | while read dylib; do
echo "Checking: $(basename "$dylib")"
codesign --verify --strict "$dylib" 2>&1 || echo "❌ Failed: $dylib"
done
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The find ... | head -5 | while read dylib; do loop has two issues: (1) read will split paths on spaces (the app path contains spaces), so codesign may run on invalid truncated paths; and (2) head -5 means only 5 dylibs are verified, which undermines the goal of catching notarization failures early. Prefer a safe read method (e.g., -print0 + read -r -d '') and verify all dylibs (or clearly document why sampling is acceptable).

Copilot uses AI. Check for mistakes.
Comment on lines +214 to +222
echo "=== Verifying critical nested binaries ==="
# Check helper apps
for helper in "$APP_PATH/Contents/Frameworks/"*.app; do
if [ -d "$helper" ]; then
echo "Checking helper: $(basename "$helper")"
codesign --verify --strict "$helper" 2>&1 || echo "❌ Failed: $helper"
codesign -dvvv "$helper" 2>&1 | grep -i timestamp || echo "❌ No timestamp: $helper"
fi
done
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This verification step masks failures for nested items by using || echo ... after codesign --verify and timestamp checks in loops. That means the job can pass even if a helper/framework/dylib is unsigned or missing timestamps. Consider collecting failures and exiting non-zero at the end (or fail immediately) so notarization problems are reliably caught pre-submit.

Copilot uses AI. Check for mistakes.
Comment on lines +173 to +180
- name: Verify certificate details
if: matrix.os == 'macos-latest'
shell: bash
run: |
echo "=== Checking available signing identities ==="
security find-identity -v -p codesigning
echo ""
echo "Note: Should show 'Developer ID Application' not 'Mac App Distribution'"
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step runs security find-identity before any certificate is imported into the keychain (the workflow only sets CSC_LINK/CSC_KEY_PASSWORD; electron-builder typically imports during packaging). As a result it may show no relevant identities and still won’t block misconfiguration. Consider importing the P12 into a temporary keychain for this check or inspecting the P12 directly, and fail the step if a "Developer ID Application" identity isn’t available.

Copilot uses AI. Check for mistakes.
Comment on lines +210 to +218
echo "=== Verifying critical nested binaries ==="
# Check helper apps
for helper in "$APP_PATH/Contents/Frameworks/"*.app; do
if [ -d "$helper" ]; then
echo "Checking helper: $(basename "$helper")"
codesign --verify --strict "$helper" 2>&1 || echo "❌ Failed: $helper"
codesign -dvvv "$helper" 2>&1 | grep -i timestamp || echo "❌ No timestamp: $helper"
fi
done
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This verification step masks failures for nested items by using || echo ... after codesign --verify and timestamp checks in loops. That means the job can pass even if a helper/framework/dylib is unsigned or missing timestamps. Consider collecting failures and exiting non-zero at the end (or fail immediately) so notarization problems are reliably caught pre-submit.

Copilot uses AI. Check for mistakes.
Comment on lines +169 to +176
- name: Verify certificate details
if: matrix.os == 'macos-latest'
shell: bash
run: |
echo "=== Checking available signing identities ==="
security find-identity -v -p codesigning
echo ""
echo "Note: Should show 'Developer ID Application' not 'Mac App Distribution'"
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step runs security find-identity before any certificate is imported into the keychain (the workflow only sets CSC_LINK/CSC_KEY_PASSWORD; electron-builder typically imports during packaging). As a result it may show no relevant identities and still won’t block misconfiguration. Consider importing the P12 into a temporary keychain for this check or inspecting the P12 directly, and fail the step if a "Developer ID Application" identity isn’t available.

Copilot uses AI. Check for mistakes.
Comment on lines +227 to +239
find "$APP_PATH/Contents/Frameworks" -name "*.framework" -type d -maxdepth 1 | while read framework; do
echo "Checking: $(basename "$framework")"
codesign --verify --strict "$framework" 2>&1 || echo "❌ Failed: $framework"
done

# Check dylibs
echo ""
echo "=== Checking dynamic libraries ==="
find "$APP_PATH" -name "*.dylib" -type f | head -5 | while read dylib; do
echo "Checking: $(basename "$dylib")"
codesign --verify --strict "$dylib" 2>&1 || echo "❌ Failed: $dylib"
done

Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The find ... | while read framework; do loop will break on paths containing spaces (the app bundle name has spaces), causing framework to be truncated and codesign to run on the wrong path. Use a NUL-delimited pipeline (e.g., find ... -print0 + while IFS= read -r -d '' framework) or otherwise ensure paths with spaces are handled correctly.

Suggested change
find "$APP_PATH/Contents/Frameworks" -name "*.framework" -type d -maxdepth 1 | while read framework; do
echo "Checking: $(basename "$framework")"
codesign --verify --strict "$framework" 2>&1 || echo "❌ Failed: $framework"
done
# Check dylibs
echo ""
echo "=== Checking dynamic libraries ==="
find "$APP_PATH" -name "*.dylib" -type f | head -5 | while read dylib; do
echo "Checking: $(basename "$dylib")"
codesign --verify --strict "$dylib" 2>&1 || echo "❌ Failed: $dylib"
done
find "$APP_PATH/Contents/Frameworks" -maxdepth 1 -type d -name "*.framework" -print0 | while IFS= read -r -d '' framework; do
echo "Checking: $(basename "$framework")"
codesign --verify --strict "$framework" 2>&1 || echo "❌ Failed: $framework"
done
# Check dylibs
echo ""
echo "=== Checking dynamic libraries ==="
find "$APP_PATH" -name "*.dylib" -type f -print0 | {
count=0
while IFS= read -r -d '' dylib; do
echo "Checking: $(basename "$dylib")"
codesign --verify --strict "$dylib" 2>&1 || echo "❌ Failed: $dylib"
count=$((count + 1))
if [ "$count" -ge 5 ]; then
break
fi
done
}

Copilot uses AI. Check for mistakes.
# Check frameworks
echo ""
echo "=== Checking frameworks ==="
find "$APP_PATH/Contents/Frameworks" -name "*.framework" -type d -maxdepth 1 | while read framework; do
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The find ... | while read framework; do loop will break on paths containing spaces (the app bundle name has spaces), causing framework to be truncated and codesign to run on the wrong path. Use a NUL-delimited pipeline (e.g., find ... -print0 + while IFS= read -r -d '' framework) or otherwise ensure paths with spaces are handled correctly.

Suggested change
find "$APP_PATH/Contents/Frameworks" -name "*.framework" -type d -maxdepth 1 | while read framework; do
find "$APP_PATH/Contents/Frameworks" -maxdepth 1 -type d -name "*.framework" -print0 | while IFS= read -r -d '' framework; do

Copilot uses AI. Check for mistakes.
Comment on lines +228 to +234
# Check dylibs
echo ""
echo "=== Checking dynamic libraries ==="
find "$APP_PATH" -name "*.dylib" -type f | head -5 | while read dylib; do
echo "Checking: $(basename "$dylib")"
codesign --verify --strict "$dylib" 2>&1 || echo "❌ Failed: $dylib"
done
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The find ... | head -5 | while read dylib; do loop has two issues: (1) read will split paths on spaces (the app path contains spaces), so codesign may run on invalid truncated paths; and (2) head -5 means only 5 dylibs are verified, which undermines the goal of catching notarization failures early. Prefer a safe read method (e.g., -print0 + read -r -d '') and verify all dylibs (or clearly document why sampling is acceptable).

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +12
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding com.apple.security.cs.allow-dyld-environment-variables weakens the hardened runtime by allowing DYLD_* environment variables (commonly restricted to prevent injection). If this is strictly required, consider documenting why in the plist and confirming it’s the minimal entitlement needed; otherwise, avoid enabling it globally for the whole app bundle.

Suggested change
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 9, 2026

Bundle Size Report 📦

Bundle Size
Main Process 4.84 MB
Renderer JS 683.67 KB
Renderer CSS 76.32 KB
Total 5.58 MB

Bundle Analysis Reports

The detailed bundle analysis reports are available in the workflow artifacts:

  • 📊 Main Process: stats-main.html
  • 📊 Renderer Process: stats-renderer.html

Download the artifacts from the workflow run to view interactive visualizations.


Bundle size tracking is now active! This helps prevent bundle bloat.

@Power-Maverick Power-Maverick merged commit 854cc6f into dev Feb 9, 2026
@Power-Maverick Power-Maverick deleted the copilot/fix-macos-notarization-errors branch February 9, 2026 15:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants