Skip to content

Commit c1deace

Browse files
authored
fix: updating SignOptions typesafety and leverage optionsForFile for entitlements (#7491)
1 parent 4ab5f98 commit c1deace

15 files changed

+157
-127
lines changed

.changeset/old-melons-taste.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"app-builder-lib": patch
3+
---
4+
5+
fix: updating SignOptions to leverage `optionsForFile` for entitlements

docs/configuration/mac.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ The top-level [mac](configuration.md#Configuration-mac) key contains set of opti
8484
<p><code id="MacConfiguration-gatekeeperAssess">gatekeeperAssess</code> = <code>false</code> Boolean - Whether to let @electron/osx-sign validate the signing or not.</p>
8585
</li>
8686
<li>
87-
<p><code id="MacConfiguration-strictVerify">strictVerify</code> = <code>true</code> Array&lt;String&gt; | String | Boolean - Whether to let @electron/osx-sign verify the contents or not.</p>
87+
<p><code id="MacConfiguration-strictVerify">strictVerify</code> = <code>true</code> Boolean - Whether to let @electron/osx-sign verify the contents or not.</p>
8888
</li>
8989
<li>
9090
<p><code id="MacConfiguration-signIgnore">signIgnore</code> Array&lt;String&gt; | String | “undefined” - Regex or an array of regex’s that signal skipping signing a file.</p>

packages/app-builder-lib/scheme.json

+4-30
Original file line numberDiff line numberDiff line change
@@ -2776,22 +2776,9 @@
27762776
]
27772777
},
27782778
"strictVerify": {
2779-
"anyOf": [
2780-
{
2781-
"items": {
2782-
"type": "string"
2783-
},
2784-
"type": "array"
2785-
},
2786-
{
2787-
"type": [
2788-
"string",
2789-
"boolean"
2790-
]
2791-
}
2792-
],
27932779
"default": true,
2794-
"description": "Whether to let @electron/osx-sign verify the contents or not."
2780+
"description": "Whether to let @electron/osx-sign verify the contents or not.",
2781+
"type": "boolean"
27952782
},
27962783
"target": {
27972784
"anyOf": [
@@ -3414,22 +3401,9 @@
34143401
]
34153402
},
34163403
"strictVerify": {
3417-
"anyOf": [
3418-
{
3419-
"items": {
3420-
"type": "string"
3421-
},
3422-
"type": "array"
3423-
},
3424-
{
3425-
"type": [
3426-
"string",
3427-
"boolean"
3428-
]
3429-
}
3430-
],
34313404
"default": true,
3432-
"description": "Whether to let @electron/osx-sign verify the contents or not."
3405+
"description": "Whether to let @electron/osx-sign verify the contents or not.",
3406+
"type": "boolean"
34333407
},
34343408
"target": {
34353409
"anyOf": [

packages/app-builder-lib/src/macPackager.ts

+50-33
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import BluebirdPromise from "bluebird-lst"
22
import { deepAssign, Arch, AsyncTaskManager, exec, InvalidConfigurationError, log, use, getArchSuffix } from "builder-util"
33
import { signAsync } from "@electron/osx-sign"
4-
import { SignOptions } from "@electron/osx-sign/dist/cjs/types"
4+
import { PerFileSignOptions, SignOptions } from "@electron/osx-sign/dist/cjs/types"
55
import { mkdir, readdir } from "fs/promises"
66
import { Lazy } from "lazy-val"
77
import * as path from "path"
@@ -268,8 +268,9 @@ export default class MacPackager extends PlatformPackager<MacConfiguration> {
268268
)
269269
log.info("Signing addtional user-defined binaries: " + JSON.stringify(binaries, null, 1))
270270
}
271+
const customSignOptions = (isMas ? masOptions : this.platformSpecificBuildOptions) || this.platformSpecificBuildOptions
271272

272-
const signOptions: any = {
273+
const signOptions: SignOptions = {
273274
identityValidation: false,
274275
// https://github.com/electron-userland/electron-builder/issues/1699
275276
// kext are signed by the chipset manufacturers. You need a special certificate (only available on request) from Apple to be able to sign kext.
@@ -297,27 +298,22 @@ export default class MacPackager extends PlatformPackager<MacConfiguration> {
297298
identity: identity ? identity.name : undefined,
298299
type,
299300
platform: isMas ? "mas" : "darwin",
300-
version: this.config.electronVersion,
301+
version: this.config.electronVersion || undefined,
301302
app: appPath,
302303
keychain: keychainFile || undefined,
303304
binaries,
304-
timestamp: isMas ? masOptions?.timestamp : options.timestamp,
305-
requirements: isMas || this.platformSpecificBuildOptions.requirements == null ? undefined : await this.getResource(this.platformSpecificBuildOptions.requirements),
306-
// https://github.com/electron-userland/electron-osx-sign/issues/196
307-
// will fail on 10.14.5+ because a signed but unnotarized app is also rejected.
308-
"gatekeeper-assess": options.gatekeeperAssess === true,
309305
// https://github.com/electron-userland/electron-builder/issues/1480
310306
strictVerify: options.strictVerify,
311-
hardenedRuntime: isMas ? masOptions && masOptions.hardenedRuntime === true : options.hardenedRuntime !== false,
307+
optionsForFile: await this.getOptionsForFile(appPath, isMas, customSignOptions),
308+
provisioningProfile: customSignOptions.provisioningProfile || undefined,
312309
}
313310

314-
await this.adjustSignOptions(signOptions, masOptions)
315311
log.info(
316312
{
317313
file: log.filePath(appPath),
318314
identityName: identity.name,
319315
identityHash: identity.hash,
320-
provisioningProfile: signOptions["provisioning-profile"] || "none",
316+
provisioningProfile: signOptions.provisioningProfile || "none",
321317
},
322318
"signing"
323319
)
@@ -342,37 +338,58 @@ export default class MacPackager extends PlatformPackager<MacConfiguration> {
342338
return true
343339
}
344340

345-
private async adjustSignOptions(signOptions: any, masOptions: MasConfiguration | null) {
341+
private async getOptionsForFile(appPath: string, isMas: boolean, customSignOptions: MacConfiguration) {
346342
const resourceList = await this.resourceList
347-
const customSignOptions = masOptions || this.platformSpecificBuildOptions
348-
const entitlementsSuffix = masOptions == null ? "mac" : "mas"
343+
const entitlementsSuffix = isMas ? "mas" : "mac"
349344

350-
let entitlements = customSignOptions.entitlements
351-
if (entitlements == null) {
352-
const p = `entitlements.${entitlementsSuffix}.plist`
353-
if (resourceList.includes(p)) {
354-
entitlements = path.join(this.info.buildResourcesDir, p)
355-
} else {
356-
entitlements = getTemplatePath("entitlements.mac.plist")
345+
const getEntitlements = (filePath: string) => {
346+
// check if root app, then use main entitlements
347+
if (filePath === appPath) {
348+
if (customSignOptions.entitlements) {
349+
return customSignOptions.entitlements
350+
}
351+
const p = `entitlements.${entitlementsSuffix}.plist`
352+
if (resourceList.includes(p)) {
353+
return path.join(this.info.buildResourcesDir, p)
354+
} else {
355+
return getTemplatePath("entitlements.mac.plist")
356+
}
357357
}
358-
}
359-
signOptions.entitlements = entitlements
360358

361-
let entitlementsInherit = customSignOptions.entitlementsInherit
362-
if (entitlementsInherit == null) {
359+
// It's a login helper...
360+
if (filePath.includes("Library/LoginItems")) {
361+
return customSignOptions.entitlementsLoginHelper
362+
}
363+
364+
// Only remaining option is that it's inherited entitlements
365+
if (customSignOptions.entitlementsInherit) {
366+
return customSignOptions.entitlementsInherit
367+
}
363368
const p = `entitlements.${entitlementsSuffix}.inherit.plist`
364369
if (resourceList.includes(p)) {
365-
entitlementsInherit = path.join(this.info.buildResourcesDir, p)
370+
return path.join(this.info.buildResourcesDir, p)
366371
} else {
367-
entitlementsInherit = getTemplatePath("entitlements.mac.plist")
372+
return getTemplatePath("entitlements.mac.plist")
368373
}
369374
}
370-
signOptions["entitlements-inherit"] = entitlementsInherit
371375

372-
if (customSignOptions.provisioningProfile != null) {
373-
signOptions["provisioning-profile"] = customSignOptions.provisioningProfile
376+
const requirements = isMas || this.platformSpecificBuildOptions.requirements == null ? undefined : await this.getResource(this.platformSpecificBuildOptions.requirements)
377+
378+
// harden by default for mac builds. Only harden mas builds if explicitly true (backward compatibility)
379+
const hardenedRuntime = isMas ? customSignOptions.hardenedRuntime === true : customSignOptions.hardenedRuntime !== false
380+
381+
const optionsForFile: (filePath: string) => PerFileSignOptions = filePath => {
382+
const entitlements = getEntitlements(filePath)
383+
const args = {
384+
entitlements: entitlements || undefined,
385+
hardenedRuntime: hardenedRuntime || undefined,
386+
timestamp: customSignOptions.timestamp || undefined,
387+
requirements: requirements || undefined,
388+
}
389+
log.debug({ file: log.filePath(filePath), ...args }, "selecting signing options")
390+
return args
374391
}
375-
signOptions["entitlements-loginhelper"] = customSignOptions.entitlementsLoginHelper
392+
return optionsForFile
376393
}
377394

378395
//noinspection JSMethodCanBeStatic
@@ -485,12 +502,12 @@ export default class MacPackager extends PlatformPackager<MacConfiguration> {
485502
if (!appleIdPassword) {
486503
throw new InvalidConfigurationError(`APPLE_APP_SPECIFIC_PASSWORD env var needs to be set`)
487504
}
488-
const options = this.generateOptions(appPath, appleId, appleIdPassword)
505+
const options = this.generateNotarizeOptions(appPath, appleId, appleIdPassword)
489506
await notarize(options)
490507
log.info(null, "notarization successful")
491508
}
492509

493-
private generateOptions(appPath: string, appleId: string, appleIdPassword: string): NotarizeOptions {
510+
private generateNotarizeOptions(appPath: string, appleId: string, appleIdPassword: string): NotarizeOptions {
494511
const baseOptions = { appPath, appleId, appleIdPassword }
495512
const options = this.platformSpecificBuildOptions.notarize
496513
if (typeof options === "boolean") {

packages/app-builder-lib/src/options/macOptions.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ export interface MacConfiguration extends PlatformSpecificBuildOptions {
167167
* Whether to let @electron/osx-sign verify the contents or not.
168168
* @default true
169169
*/
170-
readonly strictVerify?: Array<string> | string | boolean
170+
readonly strictVerify?: boolean
171171

172172
/**
173173
* Regex or an array of regex's that signal skipping signing a file.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>com.apple.security.inherit</key>
6+
<true/>
7+
</dict>
8+
</plist>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>com.apple.security.inherit</key>
6+
<true/>
7+
</dict>
8+
</plist>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<!-- https://github.com/electron/electron-notarize#prerequisites -->
6+
<key>com.apple.security.cs.allow-jit</key>
7+
<true/>
8+
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
9+
<true/>
10+
<!-- https://github.com/electron-userland/electron-builder/issues/3940 -->
11+
<key>com.apple.security.cs.disable-library-validation</key>
12+
<true/>
13+
</dict>
14+
</plist>

test/src/PublishManagerTest.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createTargets, Platform } from "electron-builder"
1+
import { Arch, createTargets, Platform } from "electron-builder"
22
import { outputFile } from "fs-extra"
33
import * as path from "path"
44
import { GithubOptions, GenericServerOptions, SpacesOptions, KeygenOptions } from "builder-util-runtime"
@@ -39,7 +39,7 @@ function keygenPublisher(): KeygenOptions {
3939
test.ifNotWindows.ifDevOrLinuxCi(
4040
"generic, github and spaces",
4141
app({
42-
targets: Platform.MAC.createTarget("zip"),
42+
targets: Platform.MAC.createTarget("zip", Arch.x64),
4343
config: {
4444
generateUpdatesFilesForAllChannels: true,
4545
mac: {
@@ -67,7 +67,7 @@ test.ifMac(
6767
"mac artifactName ",
6868
app(
6969
{
70-
targets: Platform.MAC.createTarget("zip"),
70+
targets: Platform.MAC.createTarget("zip", Arch.x64),
7171
config: {
7272
// tslint:disable-next-line:no-invalid-template-strings
7373
artifactName: "${productName}_${version}_${os}.${ext}",

test/src/mac/dmgTest.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { exec } from "builder-util"
1+
import { Arch, exec } from "builder-util"
22
import { copyFile } from "builder-util/out/fs"
33
import { attachAndExecute, getDmgTemplatePath } from "dmg-builder/out/dmgUtil"
44
import { Platform } from "electron-builder"
@@ -8,7 +8,8 @@ import * as fs from "fs/promises"
88
import { assertThat } from "../helpers/fileAssert"
99
import { app, assertPack, copyTestAsset } from "../helpers/packTester"
1010

11-
const dmgTarget = Platform.MAC.createTarget("dmg")
11+
const dmgTarget = Platform.MAC.createTarget("dmg", Arch.x64)
12+
const defaultTarget = Platform.MAC.createTarget(undefined, Arch.x64)
1213

1314
test.ifMac(
1415
"dmg",
@@ -79,7 +80,7 @@ test.ifMac("custom background - new way", () => {
7980
return assertPack(
8081
"test-app-one",
8182
{
82-
targets: Platform.MAC.createTarget(),
83+
targets: defaultTarget,
8384
config: {
8485
publish: null,
8586
mac: {
@@ -116,7 +117,7 @@ test.ifAll.ifMac("retina background as 2 png", () => {
116117
return assertPack(
117118
"test-app-one",
118119
{
119-
targets: Platform.MAC.createTarget(),
120+
targets: defaultTarget,
120121
config: {
121122
publish: null,
122123
},
@@ -149,7 +150,7 @@ test.ifAll.ifMac("retina background as 2 png", () => {
149150

150151
test.skip.ifMac.ifAll("no Applications link", () => {
151152
return assertPack("test-app-one", {
152-
targets: Platform.MAC.createTarget(),
153+
targets: defaultTarget,
153154
config: {
154155
publish: null,
155156
productName: "NoApplicationsLink",
@@ -258,7 +259,7 @@ test.ifAll.ifMac(
258259

259260
test.ifAll.ifMac("disable dmg icon (light), bundleVersion", () => {
260261
return assertPack("test-app-one", {
261-
targets: Platform.MAC.createTarget(),
262+
targets: defaultTarget,
262263
config: {
263264
publish: null,
264265
dmg: {

test/src/mac/macArchiveTest.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { exec } from "builder-util"
1+
import { Arch, exec } from "builder-util"
22
import { parseXml } from "builder-util-runtime"
33
import { Platform } from "electron-builder"
44
import { outputFile } from "fs-extra"
@@ -22,7 +22,7 @@ test.ifAll.ifMac(
2222
"empty installLocation",
2323
app(
2424
{
25-
targets: Platform.MAC.createTarget("pkg"),
25+
targets: Platform.MAC.createTarget("pkg", Arch.x64),
2626
config: {
2727
pkg: {
2828
installLocation: "",
@@ -42,7 +42,7 @@ test.ifAll.ifMac(
4242
"extraDistFiles",
4343
app(
4444
{
45-
targets: Platform.MAC.createTarget("zip"),
45+
targets: Platform.MAC.createTarget("zip", Arch.x64),
4646
config: {
4747
mac: {
4848
extraDistFiles: "extra.txt",
@@ -62,7 +62,7 @@ test.ifAll.ifMac(
6262
"pkg extended configuration",
6363
app(
6464
{
65-
targets: Platform.MAC.createTarget("pkg"),
65+
targets: Platform.MAC.createTarget("pkg", Arch.x64),
6666
config: {
6767
pkg: {
6868
isRelocatable: false,
@@ -110,7 +110,7 @@ test.ifAll.ifMac(
110110
"pkg scripts",
111111
app(
112112
{
113-
targets: Platform.MAC.createTarget("pkg"),
113+
targets: Platform.MAC.createTarget("pkg", Arch.x64),
114114
},
115115
{
116116
signed: false,

0 commit comments

Comments
 (0)