@electron/osx-sign Documentation

repository·main·Indexed 20 days ago

https://github.com/electron/osx-sign

A utility for codesigning Electron macOS applications and creating flat (.pkg) installer packages. It simplifies signing for both the Mac App Store and direct distribution, providing a JavaScript API and CLI tools (electron-osx-sign and electron-osx-flat). Features include support for provisioning profiles, custom signing options via optionsForFile, and a pure-JavaScript implementation for faster, cross-platform creation of unsigned packages.

Tokens
7.5K
Snippets
24
Records
30
Agent score
68%

What's inside @electron/osx-sign

  1. Use the electron-osx-flat CLI to build flat installers

    main

    The electron-osx-flat command is used to build product packages (flat installers) for Electron applications. It can use either Apple's native pkgbuild/productbuild tools or a bundled pure-JavaScript implementation.

    Basic Syntax:

    electron-osx-flat <path-to-app-bundle> [options]

    Key Requirements:

    • The app argument must be a path to an application package with the .app extension.
    • If you are using the js implementation on a non-macOS platform, you must use the --noIdentity flag.
    electron-osx-flat app.app
  2. Prerequisites for macOS Code Signing

    main

    To use @electron/osx-sign for code signing, ensure you meet the following requirements:

    • Apple Developer Program: You must be a registered member.
    • Xcode: Installed from the Mac App Store.
    • Xcode Command Line Tools: Install via xcode-select --install.
    • App Store Connect: Required if distributing via the Mac App Store.
    • App Metadata: Your app must have a unique Bundle ID and a version number.

    Required Certificates

    Depending on your distribution method, you need specific certificates installed in your keychain (ideally the system default keychain):

    Distribution MethodRequired Certificates
    Mac App Store3rd Party Mac Developer Application: * (*) and 3rd Party Mac Developer Installer: * (*)
    Outside App StoreDeveloper ID Application: * (*) and Developer ID Installer: * (*)
  3. Migrate from `electron-osx-sign` to `@electron/osx-sign`

    main

    When migrating from the legacy electron-osx-sign package to @electron/osx-sign, you should adopt the new API surface and defaults to ensure a more secure and safe application.

    If you need to maintain identical behavior to your old configuration, you must map the old flat options object to the new structure. Key changes include:

    • Entitlements: The specific flags 'entitlements-inherit' and 'entitlements-loginhelper' have been removed. Instead, use the optionsForFile callback to return specific entitlements for different files.
    • Signature Flags: The 'restrict' flag has been removed; use optionsForFile.signatureFlags instead.
    • Signature Size: The 'signature-size' option has been removed.
    • Naming Conventions: Many keys have moved from kebab-case (e.g., identity-validation) to camelCase (e.g., identityValidation).
    const oldOptions = {
      app: 'path/to/app',
      binaries: ['a', 'b'],
      entitlements: 'path/to/entitlements',
      'entitlements-inherit': 'path/to/inherited-entitlements', // Removed, use optionsForFile.entitlements
      'entitlements-loginhelper': 'path/to/login-entitlements', // Removed, use optionsForFile.entitlements
      entitlementsForFile: (filePath, codesignArgs) => 'path/to/different-entitlements',
      'gatekeeper-assess': true,
      hardenedRuntime: true,
      identity: 'My Identity',
      'identity-validation': false,
      keychain: 'Login.keychain',
      ignore: /bad-files/,
      platform: 'darwin',
      'pre-auto-entitlements': true,
      'pre-embed-provisioning-profile': true,
      provisioning-profile: 'path/to/provisioning-profile',
      requirements: 'custom-requirements',
      restrict: true, // Removed, use optionsForFile.signatureFlags
      'signature-flags': 'foo,bar,thing',
      'signature-size': 12000, // Removed
      'strict-verify': true,
      timestamp: 'https://timestamp-server',
      type: 'distribution',
      version: '1.2.3',
    }
    
    const newOptions = {
      app: oldOptions.app,
      binaries: oldOptions.binaries,
      optionsForFile: (filePath) => ({
        // Ensure you return the right entitlements path here based on the file being signed.
        // E.g. The Login Helper should get oldOptions['entitlements-loginhelper']
        entitlements: getEntitlementsForFile(filePath),
        hardenedRuntime: oldOptions.hardenedRuntime,
        signatureFlags: oldOptions['signature-flags'],
        timestamp: oldOptions.timestamp,
      }),
      identity: oldOptions.identity,
      identityValidation: oldOptions['identity-validation'],
      keychain: oldOptions.keychain,
      ignore: oldOptions.ignore,
      platform: oldOptions.platform,
      preAutoEntitlements: oldOptions['pre-auto-entitlements'],
      preEmbedProvisioningProfile: oldOptions['pre-embed-provisioning-profile'],
      provisioningProfile: oldOptions['provisioning-profile'],
      strictVerify: oldOptions['strict-verify'],
      type: oldOptions.type,
      version: oldOptions.version,
    }
  4. Use `batchCodesignCalls` for faster signing

    main

    When batchCodesignCalls is set to true, the library optimizes the signing process. Instead of calling codesign for every single file, it groups files that share the same signing arguments and depth in the file tree, executing them in batches. This can significantly reduce the time required to sign large application bundles.

    await sign({
      app: '/path/to/YourApp.app',
      batchCodesignCalls: true
    });
  5. Configure Mac App Store (MAS) signing

    main

    When signing for the Mac App Store, you must provide a Provisioning Profile. Use the following options:

    • platform: Set to "mas" (auto-detected if using Packager/Forge).
    • type: Set to "distribution" (default) for App Store Connect submission.
    • provisioningProfile: Path to your .provisionprofile (defaults to current working directory).
    • keychain: Name of the keychain (defaults to system default login keychain).

    Note on running distribution builds locally: By default, @electron/osx-sign adds com.apple.developer.team-identifier to a temporary copy of your entitlements, which prevents the app from running locally. To allow local execution, set preAutoEntitlements: false and manually add ElectronTeamID to your Info.plist and com.apple.security.application-groups to your entitlements file.

    import { sign } from '@electron/osx-sign'
    const opts = {
      app: 'path/to/my.app',
      platform: "mas",
      type: "distribution",
      provisioningProfile: 'path/to/my.provisionprofile',
      keychain: 'my-keychain',
    };
    sign(opts)
      .then(() => {
        // Application signed
      })
      .catch((err) => {
        // Handle error
      });
  6. Use pure-JavaScript implementation for faster packaging

    main

    You can switch from the native productbuild binary to a bundled pure-JavaScript implementation by setting implementation: 'js'. This is typically 4–5× faster and can run on Linux/Windows for unsigned packages.

    Limitations of the JS implementation:

    • Does not preserve extended attributes.
    • Info.plist must be XML (binary property lists are rejected).
    • Hardlinked files are stored as independent copies.
    • Files larger than 4 GB are rejected (32-bit size limit).
    • When a signing identity is provided, it uses productsign, which still requires macOS.
    import { flat } from '@electron/osx-sign';
    
    await flat({
      app: 'path/to/my.app',
      implementation: 'js',
    });
  7. Sign a macOS app with sign()

    main

    The sign function uses the codesign utility to sign your .app bundle. The only mandatory option is app (the path to your .app package).

    import { sign } from '@electron/osx-sign'
    const opts = {
      app: 'path/to/my.app'
    };
    sign(opts)
      .then(function () {
        // Application signed
      })
      .catch(function (err) {
        // Handle the error
      })
  8. Apply specific signing options to individual files with optionsForFile

    main

    If certain subresources (like .jar files) require specific flags like --deep, use the optionsForFile callback. This function receives the filePath and a context object containing the resolved platform ('darwin' or 'mas').

    import { sign } from '@electron/osx-sign'
    import path from 'path'
    
    sign({
      app: 'path/to/my.app',
      optionsForFile: (filePath, { platform }) => {
        if (path.basename(filePath) === 'myStrangeFile.jar') {
          return {
            additionalArguments: ['--deep'],
          };
        }
        return null;
      },
    });
  9. Create flat installer packages with flat()

    main

    The flat function creates .pkg installers using the productbuild utility. The only mandatory option is app (the path to your .app package).

    import { flat } from '@electron/osx-sign'
    
    flat({
      app: 'path/to/my.app'
    })
      .then(function () {
        // Application flattened
      })
      .catch(function (err) {
        // Handle the error
      })