fix(mac): allow ad-hoc identities for codesigning (#9007)

This commit is contained in:
Kenneth Chew 2025-04-09 23:45:43 -04:00 committed by GitHub
parent 106640dd42
commit bff46ec41c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 29 additions and 10 deletions

View file

@ -0,0 +1,5 @@
---
"app-builder-lib": patch
---
fix(mac): allow ad-hoc identities for codesigning

View file

@ -2702,7 +2702,7 @@
]
},
"identity": {
"description": "The name of certificate to use when signing. Consider using environment variables [CSC_LINK or CSC_NAME](./code-signing.md) instead of specifying this option.\nMAS installer identity is specified in the [mas](./mas.md).",
"description": "The name of certificate to use when signing. Consider using environment variables [CSC_LINK or CSC_NAME](./code-signing.md) instead of specifying this option.\nMAS installer identity is specified in the [mas](./mas.md).\n\nSet to `-` to use an ad-hoc identity for signing. Set to `null` to skip signing entirely.",
"type": [
"null",
"string"
@ -3334,7 +3334,7 @@
]
},
"identity": {
"description": "The name of certificate to use when signing. Consider using environment variables [CSC_LINK or CSC_NAME](./code-signing.md) instead of specifying this option.\nMAS installer identity is specified in the [mas](./mas.md).",
"description": "The name of certificate to use when signing. Consider using environment variables [CSC_LINK or CSC_NAME](./code-signing.md) instead of specifying this option.\nMAS installer identity is specified in the [mas](./mas.md).\n\nSet to `-` to use an ad-hoc identity for signing. Set to `null` to skip signing entirely.",
"type": [
"null",
"string"

View file

@ -88,10 +88,11 @@ export async function reportError(isMas: boolean, certificateTypes: CertType[],
.join("\n")
}
const skipMessage = "skipped macOS application code signing"
if (isMas || isForceCodeSigning) {
throw new Error(Logger.createMessage("skipped macOS application code signing", logFields, "error", it => it))
throw new Error(Logger.createMessage(skipMessage, logFields, "error", it => it))
} else {
log.warn(logFields, "skipped macOS application code signing")
log.warn(logFields, skipMessage)
}
}

View file

@ -1,6 +1,7 @@
import { notarize } from "@electron/notarize"
import { NotarizeOptionsNotaryTool, NotaryToolKeychainCredentials } from "@electron/notarize/lib/types"
import { PerFileSignOptions, SignOptions } from "@electron/osx-sign/dist/cjs/types"
import { Identity } from "@electron/osx-sign/dist/cjs/util-identities"
import { Arch, AsyncTaskManager, copyFile, deepAssign, exec, getArchSuffix, InvalidConfigurationError, log, orIfFileNotExist, statOrNull, unlinkIfExists, use } from "builder-util"
import { MemoLazy, Nullish } from "builder-util-runtime"
import * as fs from "fs/promises"
@ -8,7 +9,7 @@ import { mkdir, readdir } from "fs/promises"
import { Lazy } from "lazy-val"
import * as path from "path"
import { AppInfo } from "./appInfo"
import { CertType, CodeSigningInfo, createKeychain, CreateKeychainOptions, findIdentity, Identity, isSignAllowed, removeKeychain, reportError, sign } from "./codeSign/macCodeSign"
import { CertType, CodeSigningInfo, createKeychain, CreateKeychainOptions, findIdentity, isSignAllowed, removeKeychain, reportError, sign } from "./codeSign/macCodeSign"
import { DIR_TARGET, Platform, Target } from "./core"
import { AfterPackContext, ElectronPlatformName } from "./index"
import { MacConfiguration, MasConfiguration } from "./options/macOptions"
@ -229,7 +230,7 @@ export class MacPackager extends PlatformPackager<MacConfiguration> {
}
}
private async sign(appPath: string, outDir: string | null, masOptions: MasConfiguration | null, arch: Arch | null): Promise<boolean> {
private async sign(appPath: string, outDir: string | null, masOptions: MasConfiguration | null, arch: Arch): Promise<boolean> {
if (!isSignAllowed()) {
return false
}
@ -237,12 +238,16 @@ export class MacPackager extends PlatformPackager<MacConfiguration> {
const isMas = masOptions != null
const options = masOptions == null ? this.platformSpecificBuildOptions : masOptions
const qualifier = options.identity
const fallBackToAdhoc = (arch === Arch.arm64 || arch === Arch.universal) && !this.forceCodeSigning
if (qualifier === null) {
if (this.forceCodeSigning) {
throw new InvalidConfigurationError("identity explicitly is set to null, but forceCodeSigning is set to true")
}
log.info({ reason: "identity explicitly is set to null" }, "skipped macOS code signing")
if (fallBackToAdhoc) {
log.warn("arm64 requires signing, but identity is set to null and signing is being skipped")
}
return false
}
@ -268,7 +273,13 @@ export class MacPackager extends PlatformPackager<MacConfiguration> {
}
}
if (!options.sign && identity == null) {
const noIdentity = !options.sign && identity == null
if (qualifier === "-") {
identity = new Identity("-", undefined)
} else if (noIdentity && fallBackToAdhoc) {
log.warn(null, "falling back to ad-hoc signature for macOS application code signing")
identity = new Identity("-", undefined)
} else if (noIdentity) {
await reportError(isMas, certificateTypes, qualifier, keychainFile, this.forceCodeSigning)
return false
}
@ -514,7 +525,7 @@ export class MacPackager extends PlatformPackager<MacConfiguration> {
await Promise.all(
directories.map(async (file: string) => {
if (shouldSign(file)) {
await this.sign(path.join(sourceDirectory, file), null, null, null)
await this.sign(path.join(sourceDirectory, file), null, null, packContext.arch)
}
})
)

View file

@ -21,6 +21,8 @@ export interface MacConfiguration extends PlatformSpecificBuildOptions {
/**
* The name of certificate to use when signing. Consider using environment variables [CSC_LINK or CSC_NAME](./code-signing.md) instead of specifying this option.
* MAS installer identity is specified in the [mas](./mas.md).
*
* Set to `-` to use an ad-hoc identity for signing. Set to `null` to skip signing entirely.
*/
readonly identity?: string | null

View file

@ -1,6 +1,6 @@
macOS code signing is supported. If the configuration values are provided correctly in your package.json, then signing should be automatically executed.
On a macOS development machine, a valid and appropriate identity from your keychain will be automatically used.
On a macOS development machine, a valid and appropriate identity from your keychain will be automatically used. If no such identity exists, the default behavior depends on the target architecture. On ARM or universal builds, an ad-hoc signature will be applied by default. On Intel-only builds, the default behavior is to not sign at all.
!!! tip
See article [Notarizing your Electron application](https://kilianvalkhof.com/2019/electron/notarizing-your-electron-application/).
@ -23,7 +23,7 @@ On a macOS development machine, a valid and appropriate identity from your keych
To disable Code Signing when building for macOS leave all the above vars unset except for `CSC_IDENTITY_AUTO_DISCOVERY` which needs to be set to `false`. This can be done by running `export CSC_IDENTITY_AUTO_DISCOVERY=false`.
Another way — set `mac.identity` to `null`. You can pass aditional configuration using CLI as well: `-c.mac.identity=null`.
Another way — set `mac.identity` to `null`. You can pass additional configuration using CLI as well: `-c.mac.identity=null`. If you are building for ARM, you likely actually want to use ad-hoc signing, in which case you should set `mac.identity` to `-`.
## Code Signing and Notarization Tutorial
Thank you to a community member for putting this together.