Versions:
electron
: 5.0.6
electron-builder
: 21.0.11
electron-notarize
: 0.1.1
electron-webpack
: 2.7.4
Working on
: MacOS Catalina 10.15 Beta 3 (19A501i)
Xcode
: Xcode 11 beta 3
What I'm trying to do:
Sign and notarize an electron, web-packed, react desktop application for distribution outside the mac store.
Problem and exact case of error:
Build the app signed, hardened runtime, notarize: (build, sign and notatrize successful) error below when opening app ❌
In both the error cases I've run:
1/ Verify code signing ✅
test.app: valid on disk
test.app: satisfies its Designated Requirement
2/ Verify code notarization ✅
test.app: accepted
source=Notarized Developer ID
origin=Developer ID Application: XXX, Inc. (XXXXXXXXXX)
<?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.cs.allow-unsigned-executable-memory</key>
<true/>
</dict>
Process: Test [7467]
Path: /Users/USER/Documents/*/Test.app/Contents/MacOS/Test
Identifier: ai.XXXX.desktop
Version: 0.0.4 (0.0.4)
Code Type: X86-64 (Native)
Parent Process: ??? [1]
Responsible: Test [7467]
User ID: 501
Date/Time: 2019-07-10 16:44:52.073 -0400
OS Version: Mac OS X 10.15 (19A501i)
Report Version: 12
Bridge OS Version: 4.0 (17P50496d)
Anonymous UUID: 259AA2B3-5AA8-D576-9F9B-EF113BC33FAD
Sleep/Wake UUID: BFEDF03B-3097-40F1-9CC0-19B87A69E03E
Time Awake Since Boot: 27000 seconds
Time Since Wake: 11000 seconds
System Integrity Protection: enabled
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (Code Signature Invalid)
Exception Codes: 0x0000000000000032, 0x00001a9c2b202040
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: Namespace CODESIGNING, Code 0x2
...
Logical CPU: 6
Error Code: 0x00000015 (invalid protections for user instruction write)
Trap Number: 14
Confirmed same issue happening to us. I'm not sure what to even do to work around this.
is this the fix? https://github.com/electron-userland/electron-builder/pull/3926
Further info:
You need at least the following entitlements:
<?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.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/>
</dict>
</plist>
Further info from https://medium.com/@TwitterArchiveEraser/notarize-electron-apps-7a5f988406db
Make sure to try out starting the app after this process, if some entitlements are missing, the app might be broken after notarization.
@itsthisjustin tried all sorts of entitlements, including the ones above, not the fix. Also tried gatekeeper access to false and afterSign hook to notarize before making the DMG; still not the fix. The only variable that fixes this is turning hardened runtime off; but that means you can't notarize.
I've tried this entire process on a non-webpacked electron app and that seems to work fine; feels like it could be connected.
I've also tried setting the sandboxed entitlement; while the app opens in this scenario and the Code Signature Invalid
error goes away, but it leads to a different crash error. Expected since the app I'm working on is not ready to be sandboxed yet.
@UdaraJay entitlements got rid of the sign error but yeah my UI crashes on start now
Hey, @itsthisjustin - wondering what MacOS you use? and Xcode version? Curious if it's an xcode issue.
@UdaraJay I installed the latest Xcode beta today actually in order to get notarization working. So 11 beta 3. I'm on OSX 10.14.5. I have this running in Travis CI as well.
Update: Tested on xcode 10.2 and same issue
Yes, the issue I'm having in #3989 seems exactly the same, except I'm still using electron 4.2.6 and I'm building on an older Mac (OSX 10.13.6, according to Apple's own documentation this is the minimum version able to notarize apps - and I verified that using Xcode to build a simple native app it works perfectly well). Also, my app doesn't use webpack but only simple old-school html/css/js.
Both signature and notarization seems ok on my app, and even the error report seems the same:
Process: TestApp [4615]
Path: /Applications/TestApp.app/Contents/MacOS/TestApp
Identifier: com.mycompany.test-app
Version: 1.4.4 (1.4.4)
Code Type: X86-64 (Native)
Parent Process: ??? [1]
Responsible: TestApp [4615]
User ID: 501
Date/Time: 2019-07-10 18:02:04.255 +0200
OS Version: Mac OS X 10.14.5 (18F132)
Report Version: 12
Anonymous UUID: 516B346A-7835-6066-F0D6-F79409DF2C59
[...]
System Integrity Protection: enabled
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (Code Signature Invalid)
Exception Codes: 0x0000000000000032, 0x00002f36dcf86660
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: Namespace CODESIGNING, Code 0x2
kernel messages:
VM Regions Near 0x2f36dcf86660:
Memory Tag 255 00002f36dcf83000-00002f36dcf84000 [ 4K] ---/rwx SM=NUL
--> Memory Tag 255 00002f36dcf84000-00002f36dcfff000 [ 492K] r-x/rwx SM=COW
Memory Tag 255 00002f36dcfff000-00002f36e4f69000 [127.4M] ---/rwx SM=NUL
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 ??? 0x00002f36dcf86660 0 + 51912682006112
1 com.github.Electron.framework 0x00000001016b9a41 0x1002f3000 + 20736577
2 com.github.Electron.framework 0x00000001016b9778 v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*) + 152
3 com.github.Electron.framework 0x0000000101a7d4fc v8::Script::Run(v8::Local<v8::Context>) + 492
4 com.github.Electron.framework 0x00000001050c63af 0x1002f3000 + 81605551
5 com.github.Electron.framework 0x00000001050c5f0f node::LoadEnvironment(node::Environment*) + 191
6 com.github.Electron.framework 0x0000000102067968 0x1002f3000 + 30886248
7 com.github.Electron.framework 0x0000000101fed395 0x1002f3000 + 30385045
8 com.github.Electron.framework 0x0000000100d0042a 0x1002f3000 + 10540074
9 com.github.Electron.framework 0x0000000100d05afa 0x1002f3000 + 10562298
10 com.github.Electron.framework 0x0000000100cffb38 0x1002f3000 + 10537784
11 com.github.Electron.framework 0x0000000101f582f8 0x1002f3000 + 29774584
12 com.github.Electron.framework 0x000000010334dbbd 0x1002f3000 + 50703293
13 com.github.Electron.framework 0x0000000101f573a4 0x1002f3000 + 29770660
14 com.github.Electron.framework 0x00000001002f5d54 AtomMain + 84
15 com.mycompany.test-app 0x00000001002e9f10 0x1002e9000 + 3856
16 libdyld.dylib 0x00007fff603583d5 start + 1
[...]
Thread 0 crashed with X86 Thread State (64-bit):
rax: 0x0000000000000000 rbx: 0x00002f36dcf86660 rcx: 0x0000000000000000 rdx: 0x00001a9d74082201
rdi: 0x00001a9d052026f1 rsi: 0x00001a9da082e1f9 rbp: 0x00007ffeef915f90 rsp: 0x00007ffeef915ee8
r8: 0x0000000000000000 r9: 0x0000000000000000 r10: 0x0000000000000000 r11: 0x0000000106b6bd68
r12: 0x00007fa71d03b878 r13: 0x0000000106b65000 r14: 0x00001a9da082e1f9 r15: 0x00001a9d74082201
rip: 0x00002f36dcf86660 rfl: 0x0000000000010246 cr2: 0x00002f36dcf86660
Logical CPU: 0
Error Code: 0x00000015
Trap Number: 14
[...]
I tried adding all these entitlements, but with no success:
<?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.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.disable-executable-page-protection</key>
<true/>
</dict>
</plist>
I also verified that the correct entitlements are embedded in the application.
Last week I opened a DTS at Apple but even with their help we've not found a solution yet.
@UdaraJay Alright, I've finally got it working. The trick was two fold.
First:
Set both entitlements and entitlementsInherit in your mac build settings. Here's mine:
"mac": {
"hardenedRuntime": true,
"gatekeeperAssess": false,
"artifactName": "${productName}-${version}-${arch}.${ext}",
"entitlements": "mac_config/entitlements.mac.plist",
"entitlementsInherit": "mac_config/entitlements.mac.plist",
"target": [
"dmg",
"zip"
],
Then, in my entitlements file, I stripped it down to only what I need.
<?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.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
</plist>
com.apple.security.cs.allow-unsigned-executable-memory is really the key one here. Others mentioned adding another one, but I was back to the signing crash when I did that.
I've tried your same entitlements, but unfortunately my application still crashes with the same symptoms
@matteotomasoni is there any other entitlements you might need? Ive basically found this:
If you don't do the entitlementsInherit thing, your app won't load. If you mess up the entitlements with too many or too few, it'll crash with the signing error.
For instance if I add the sandbox entitlement I crash with the sign error
@itsthisjustin is there a reason for the com.apple.security.device.audio-input
entitlement? Does your app really use the audio input?
My app doesn't do anything fancy at all, but I use a couple of libraries that are like a black box to me.
If the problem is on entitlements, then is there a way (or better, a tool) to know exactly what entitlements an application needs?
@matteotomasoni ha yeah we are building https://yac.chat. So definitely needs audio.
I had the same fear as you and I think ultimately just got lucky. That’s also why the inherit property is so important. I’m not sure who at Apple thinks it’s normal to just crash an app if the entitlements are wrong though.
@itsthisjustin glad you figured it out! I've tried those entitlements and other combination (for both the entitlements and the inheritedEntitlements) with no luck. But I didn't realize having too many entitlements could cause signing errors too, that's important to note!
And yea! Truly, I wish there was a way to access more specific errors on code-signing, or at least fail more elegantly.
Hello,
Do you find a solution?
I encounter exactly the same problem.
I've been trying for more than a week for just about every possible configuration ...
I even tried to do some tests with the basic application of electron (https://electronjs.org/docs/tutorial/first-app#electron-development-in-a-nutshell) and unfortunately, I get always the same result:
All this is correct, I get each time the apple mail that says: "Your Mac software has been notarized. You can now export this software and distribute it directly to users".
The application installs correctly, and at launch I get the message inexorably:
Date/Time: 2019-07-17 10:54:31.390 +0200
OS Version: Mac OS X 10.14.5 (18F203)
Report Version: 12
Anonymous UUID: 1984F4B3-87AC-D6FD-4C5D-6A3242112EE9
Time Awake Since Boot: 1600 seconds
System Integrity Protection: enabled
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (Code Signature Invalid)
Exception Codes: 0x0000000000000032, 0x00002c32c2302040
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: Namespace CODESIGNING, Code 0x2
For now I have no idea ... So if someone at a track, I'm interested
Thank you
This suggestion from @itsthisjustin got me past the startup crash. I'm still having other issues (unable to access web content for starters) but at least things are running.
i too am having a similar problem. cant get past startup crash.
i tried using the same entitlement settings with no dice
i also tried other entitlement lines and combinations of them with no luck either.
the error log starts as /Volume/VOLUME/ because i was running it off a flash drive, both the .app file itself and the .dmg file
feeling terrible that im so close to getting the app to run yet being denied so hard
Process: Appname [874]
Path: /Volumes/VOLUME/*/Appname.app/Contents/MacOS/Appname
Identifier: com.appname.desktopapp
Version: 1.0.0 (1.0.0)
Code Type: X86-64 (Native)
Parent Process: ??? [1]
Responsible: Appname [874]
User ID: 501Date/Time: 2019-07-19 15:27:26.821 -0700
OS Version: Mac OS X 10.14.5 (18F2058)
Report Version: 12
Anonymous UUID: A4DA30A6-09EA-9677-95CD-EA316769DD4DSleep/Wake UUID: CC4B1217-0165-46A8-846E-BFA4D38C58E6
Time Awake Since Boot: 16000 seconds
System Integrity Protection: enabled
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (Code Signature Invalid)
Exception Codes: 0x0000000000000032, 0x0000108a00082040
Exception Note: EXC_CORPSE_NOTIFYTermination Reason: Namespace CODESIGNING, Code 0x2
kernel messages:
VM Regions Near 0x108a00082040:
Memory Tag 255 0000108a00081000-0000108a00082000 [ 4K] ---/rwx SM=NUL
--> Memory Tag 255 0000108a00082000-0000108a000ff000 [ 500K] r-x/rwx SM=COW
Memory Tag 255 0000108a000ff000-0000108a07fbe000 [126.7M] ---/rwx SM=NULThread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 ??? 0x0000108a00082040 0 + 18184892063808
1 com.github.Electron.framework 0x0000000103ffdad8 0x10273b000 + 25963224
2 com.github.Electron.framework 0x0000000103ffc6ce 0x10273b000 + 25958094
@starkos @HeberLemus if you don't need any specific entitlements, try removing the entitlements files and let electon-builder set the default one. That's the only way I got signing and notarizing to work on my end. (still not perfect; but it at-least gets the application to run)
@UdaraJay tried that just now, removed the properties "entitlements" and "entitlementsInherit" from the package json under the mac key, still the exact same error
also, running "codesign -d --ent :- "Appname.app/Contents/MacOS/Appname" doesnt give back anything if its supposed to set default entitlements
what are the defaults?
update: nevermind, the defaults are being set.
in the end, my build is loading with the default entitlements. the other issue i had was that i had set mac: {type: "development"}
Perfect! @HeberLemus did it start working?
@UdaraJay yes, no build issues, no startup issues and no later issues thus far. guess my problem really was that one property just like for this
update: actually there is one problem. while the file works fine when downloaded to a flashdrive and then mounted onto the mac, the .pkg isnt getting signed so when attempting to open said file it comes back as unidentified developer when attempting to download from the net
going to try and see if the AfterAllArtifactBuild hook may let me sign and notarize the .pkg beofre its done
update two: so it would seem that signing and getting it notarized works, but stapling does not
Error:
electron-notarize notarization was successful +0ms
electron-notarize attempting to staple app: /pathToFile/Appname-1.0.0.pkg +0ms
⨯ Failed to staple your application with code: 66Processing: /pathToFile/Appname-1.0.0.pkg
Properties are {
NSURLIsDirectoryKey = 0;
NSURLIsPackageKey = 0;
NSURLIsSymbolicLinkKey = 0;
NSURLLocalizedTypeDescriptionKey = "Installer package";
NSURLTypeIdentifierKey = "com.apple.installer-package-archive";
"_NSURLIsApplicationKey" = 0;
}
Could not find an appropriate "code signature" in the Appname-1.0.0.pkg installer package.
Cannot download ticket. CDHash must be set.
my method was
const cp = require('child_process');
const path = require('path');
const {notarize} = require('electron-notarize');
exports.default = async function (context) {
if (process.platform !== 'darwin') return; //dont bother if a windows build
const { artifactPaths, outDir } = context;
for (let i = 0; i< artifactPaths.length; i++) {
const APP_PATH = artifactPaths[i];
const ENTITLEMENTS_PATH = path.join(outDir, '../build/mac/entitlements.mac.plist');
const cmd =
codesign -s "${process.env.MAC_DEVELOPER_ID}" -f --entitlements "${ENTITLEMENTS_PATH}" "${APP_PATH}";
await cp.execSync(cmd, {stdio: "inherit"});
await notarize({
appBundleId:
com.appname.desktopapp,
appPath: APP_PATH,
appleId: process.env.APPLEID,
appleIdPassword: process.env.APPLEIDPASS,
});
await cp.execSync(
spctl -a -t exec -vv "${APP_PATH}", {stdio: "inherit"});
}
console.log('Build Complete');
};
if someone can suggest a cleaner way to do this i greatly appreciate it.
update 3: despite Apples documentation that even if a file doesnt have its notarization ticket stapled to it, that it should be able to get the notarization clearance from the net as stated here
After notarization completes successfully, the next time any user attempts to run your app on macOS 10.14 or later, Gatekeeper finds the ticket online...
the .pkg still refuses to open. any ideas?
@HeberLemus so I had this problem too. If signing and notarizing works anything like dmgs, then you can leave the pkg unsigned and unnotarized and the OS should see the signed and notarized application inside. I couldn't get my pkg to notarize; but I'm using a DMG for distribution currently.
@UdaraJay i also swapped back to dmg, as i asked a coworker to try and use the .pkg and his system refused to open saying unknown developer, much in the same way as if its not notarized. if i downloaded the pkg to a flash and then open the pkg from the flash on the mac after transferring it to a mac, then it would open. but if downloaded from the internet it refused
ive run into a different problem now. anytime i attempt to set entitlements other than let the defaults be set the app refuses to run. but i need the camera entitlement for my app to access webcam and audio entitlement to access microphone. any recommendations?
@HeberLemus this may be a real issue, I can't seem to get signing to work using any custom entitlements either. One thing you could try would be to look at what the exact default entitlements are and then try using those + the camera entitlements?
WOW! Thanks for this thread. Totally saved me. Couldn't figure out why navigator.mediaDevices.getUserMedia()
wasn't working after bundling for production. I used a custom entitlements file and it works just great! Thanks!
<?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.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.device.audio-input</key><true/>
<key>com.apple.security.device.camera</key><true/>
</dict>
</plist>
@patrickmichalina did you assign that to both entitlements and entitlementsInherit keys?
I used both but should it be different?
"mac": {
"entitlements": "entitlements.mac.plist",
"entitlementsInherit": "entitlements.mac.plist"
}
honestly ive never been sure. ive seen people assign the same file to them, dont understand enough about Apple security to be sure
also as ive read on other issues in this github
technically i believe are supposed to do the same thing, they just behave slightly different
allow-jit:
A Boolean value that indicates whether the app may create writable and executable memory using the MAP_JIT flag.
allow-unsigned:
A Boolean value that indicates whether the app may create writable and executable memory without the restrictions imposed by using the MAP_JIT flag.
going to try 2 builds. one without the jit flag and one exactly as you have there
@patrickmichalina tried several builds around that config, none of them open on 10.14.5. are there any other settings you are using?
ok, i believe i have gotten it to work, but in a really stupid way. i say believe because until a coworker can get back to me i cannot for the moment check if the video stream works normally. however the permission prompts for both video and audio did show up and the app did not crash on startup.
my "fix" was to find the file electron builder uses for entitlements when one is not provided (node_modules/app-builder-lib/templates/entitlements.mac.plist), modified that one by adding com.apple.security.device.audio-input and com.apple.security.device.camera to it and building it that way. that worked which is my solution for the issue #4097 i made
@develar is there a difference between the way electron-builder/electron-osx-sign accesses or reads the file we provide versus reading/using the default?
running DEBUG on both, i see when e-osx-sign does the verify and prints to the console the entitlements that were provided and there was never any errors or changes between what i provided and what was displayed
this is being built on
OS 10.14.5,
Xcode 10.2.1; build version 10E1001
electron-builder 21.1.2
electron 5.0.0
if that also helps
@HeberLemus about your previous question. I reduced the config a little and it still works for my needs.
"entitlements": "entitlements.mac.plist",
<?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.cs.allow-unsigned-executable-memory</key><true/>
<key>com.apple.security.device.audio-input</key><true/>
<key>com.apple.security.device.camera</key><true/>
</dict>
</plist>
"electron": "6.0.0-beta.14",
"electron-builder": "^21.1.5",
"electron-updater": "^4.1.2",
@UdaraJay Did you solve this issue?
Possibly related: #4179
@Jocs the issue resolved itself for me after updating electron builder, using the default entitlements and creating a new signing certificate on apple via xcode. Using custom entitlements still breaks signing for me.
i think its simply in the way the custom entitlements file gets accessed or read. because i too have the same problem as @UdaraJay. defaults are fine, customs are not. but i have no problems when i go to where the default file is located, and modify that one with what i need
I am having the same problem. Adding com.apple.security.device.microphone breaks signing for me.
@erickmaynard can you try making changes to : "node_modules/app-builder-lib/templates/entitlements.mac.plist " and see if im not the only one who can get it to work like that
@HeberLemus this also worked for me (using the default entitlements). Im not able to use a custom entitlement file. I have not had a chance to dig into the issue further, however.
Same issue. No fix but I did some tests with debug on (meaning DEBUG=electron-osx-sign
)
read-only
key and read-write
key to this entitlement file, it still seems to work: electron-osx-sign Displaying entitlements... +1ms
electron-osx-sign Executing... codesign --display --entitlements :- /Users/samuel_gagnepain/p*** lite.app +0ms
electron-osx-sign Entitlements:
<?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.cs.allow-unsigned-executable-memory</key>
<true/>
<!-- https://github.com/electron-userland/electron-builder/issues/3940 -->
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
</plist>
sandbox
key, the entitlement become corrupt:electron-osx-sign Displaying entitlements... +0ms
electron-osx-sign Executing... codesign --display --entitlements :- /Users/samuel_gagnepain/p*** lite.app +0ms
electron-osx-sign Entitlements:
bplist00�
_ com.apple.application-identifier_#com.apple.developer.team-identifier_com.apple.security.app-sandbox_%com.apple.security.application-groups_6com.apple.security.cs.allow-unsigned-executable-memory_0com.apple.security.cs.disable-library-validation_0com.apple.security.files.user-selected.read-only_1com.apple.security.files.user-selected.read-write_com.appName <b���J~��������
i never had an issue of a corrupt file. with debug on i always say it print to the console exactly what i provided for the custom entitlements file, but whatever manner it was trying to sign it would always fail to allow the app to open.
i use Webstorm as my text editor. not sure if other editors have issues correctly saving the xml file as a plist extension
- When I add the
sandbox
key, the entitlement become corrupt:
This is killing me... why in the world does it seem impossible to simultaneously enable hardenedRuntime with a sandbox entitlement?
$ codesign -d --entitlements :- release/mac/My\ App/
Executable=/Users/user/project/release/mac/My App.app/Contents/MacOS/My App
<?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.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.device.usb</key>
<true/>
<key>com.apple.security.print</key>
<true/>
<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.disable-library-validation</key>
<true/>
</dict>
</plist>
Same build command... generating mac-dev:
$ codesign -d --entitlements :- release/mas-dev/My\ App.app/
Executable=/Users/user/project/release/mas-dev/My App.app/Contents/MacOS/My App
bplist00�
_ com.apple.application-identifier_#com.apple.developer.team-identifier_com.apple.security.app-sandbox_%com.apple.security.application-groups_com.apple.security.cs.allow-jit_6com.apple.security.cs.allow-unsigned-executable-memory_0com.apple.security.cs.disable-library-validation_com.apple.security.device.usb_0com.apple.security.files.user-selected.read-only_1com.apple.security.files.user-selected.read-write_!com.apple.security.network.client_!com.apple.security.network.server_com.apple.security.print_ TEAMID.com.semireg.MyAppTEAMID � #Fl���Cc���-P[\^_`abcdefc
What is going on?
Ok, more info on this. If you google "bplist00" you get information on Apple's binary format. I understand that plists can be either XML or binary. I'm running electron-builder manually using:
DEBUG=electron-osx-sign npx electron-builder --mac mas-dev
What's interesting is that, when <key>com.apple.security.app-sandbox</key>
is defined, the debug output contains Entitlements file updated
with a path such as:
> Entitlements: /var/folders/65/7dbyc2vj55b22qb5qtxrr76c0000gn/T/tmp-entitlements-4229-0.plist +23ms
Inspecting this file reveals it's in Apple's binary format.
$ file /var/folders/65/7dbyc2vj55b22qb5qtxrr76c0000gn/T/tmp-entitlements-4229-0.plist
/var/folders/65/7dbyc2vj55b22qb5qtxrr76c0000gn/T/tmp-entitlements-4229-0.plist: Apple binary property list
If you cat
this file, the output is identical to what you see with: codesign -d --entitlements :- path/to/My App
...
You can easily convert it after the fact (not that this does any good):
$ plutil -convert xml1 /var/folders/65/7dbyc2vj55b22qb5qtxrr76c0000gn/T/tmp-entitlements-4229-0.plist
Which will yield:
$ file /var/folders/65/7dbyc2vj55b22qb5qtxrr76c0000gn/T/tmp-entitlements-4229-0.plist
/var/folders/65/7dbyc2vj55b22qb5qtxrr76c0000gn/T/tmp-entitlements-4229-0.plist: XML 1.0 document text, ASCII text
And cat
ing this file looks like what you'd expect. An entitlements plist.
My hunch is that electron-builder is wrongly code signing using a binary version of the entitlements.
Here's the location of "Entitlements file updated" https://github.com/electron-userland/electron-builder/blob/c11fa1f1033aeb7c378856d7db93369282d363f5/packages/app-builder-lib/electron-osx-sign/util-entitlements.js#L87
await executeAppBuilderAndWriteJson(["encode-plist"], {[entitlementsPath]: entitlements})
encode-plist seems to be ... I don't know where it goes. It is far down the rabbit hole of the builder-utils package. @develar, is this expected behavior?
code point for this function is here: https://github.com/electron-userland/electron-builder/blob/8e0a57d36a002fde5621f11edae17ee4eeeb8cba/packages/builder-util/src/util.ts#L337
Leads us to app-builder-bin
which is a go binary https://github.com/develar/app-builder/blob/0c35a476cb6721132fdd0de733b50aa3fc8bf72c/pkg/plist/plist.go#L22
@semireg everything leads to show that entitlements is getting encoded to binary. Are you saying the fix is that we should be converting to xml to sign?
@dannypaz, I don't know it's a fix with any certainty... it's just a promising troubleshooting path. If you look at the codesign man page it reads:
--entitlements path
When signing, take the file at the given path and embed its con-
tents in the signature as entitlement data. If the data at path
does not already begin with a suitable binary ("blob") header,
one is attached automatically.
When displaying a signature, extract any entitlement data from
the signature and write it to the path given. Use "-" to write to
standard output. By default, the binary "blob" header is
returned intact; prefix the path with a colon ":" to automati-
cally strip it off. If the signature has no entitlement data,
nothing is written (this is not an error).
https://www.manpagez.com/man/1/codesign/
This is ambiguous to me. "If the data at path does not already begin with a suitable binary..." seems like the file at path should be a binary. However, the second paragraph mentions the colon :
to automatically strip the blob.
If you go back to my codesign command above, note the colon.
$ codesign -d --entitlements :- release/mas-dev/My\ App.app/
Executable=/Users/user/project/release/mas-dev/My App.app/Contents/MacOS/My App
bplist00�
.....
And if I run that command again without the colon, presumably keeping the binary blob intact:
��qq�bplist00�
.....
Interestingly, if I redirect the output to a file:
$ codesign -d --entitlements :- release/mas-dev/My\ App.app/ >> foo.plist
$ file foo.plist
foo.plist: Apple binary property list
🤷♂
Looks like we need to change BinaryFormat to XMLFormat.
I submitted a build with manually signed XML entitlements with hardened runtime and notarized. Still rejected.
has anyone checked what the default entitlement file type is? or tried my solution above of modifying the default file with what you need and attempting to build that way, cause thats the only way i got my build to work for 10.14. havent tested 10.15 yet
@HeberLemus, fwiw, both of my hardenedRuntime "mac" builds (no sandbox) work 100% on 10.14 and 10.15. It's when sandbox is enabled for the MAS builds that everything breaks. I've had reliable mas-dev builds in the past, but today they do not run on my 10.14 box until I resign with the XML entitlements. When I submit the mas builds to apple they are always rejected because they show this error. I can't reproduce this error anywhere...
I was able to reproduce the error using mas-dev build on Catalina by creating and installing the proper provisioningprofile for that machine. At least now I'll be able to test whatever fix comes around 😄
I have nearly exhausted myself on this situation, but I've made progress. I can run my app without dlopen error, however, the BrowserWindow instance displays as a white/blank screen.
Here's the package.json scripts I use to manage my builds:
"package-mac-dev": "npm run build && electron-builder --mac zip -c.mac.identity=AB10 --config.afterSign=build/do-nothing.js",
"package-mac": "npm run build && electron-builder --mac zip -c.mac.identity=AB10",
"package-mas": "rm -rf release/mas && npm run build && electron-builder -c.mac.identity=2A4A --mac mas",
"package-mas-dev": "rm -rf release/mas-dev && npm run build && electron-builder -c.mac.identity=BEEF --mac mas-dev ",
I've abbreviated all the details, but it's worth noting you can use this command to figure out which identities relate to which build type.
$ security find-identity -v
...
6) AB10 "Developer ID Application: Team, LLC (7N)" <-- Distribute outside app store
16) 2A4A "3rd Party Mac Developer Application: Team, LLC (7N)" <-- Upload to MAS
19) BEEF "Mac Developer: Caylan (LX)" <-- Local testing of MAS builds, needs provisioning profile
Here's my package.json builder information. The trick here is to make sure that asarUnpack contains all of your native node modules. This list can be generated easily from app/package.json if you use a dual (two) package.json structure. Otherwise, just look at the uncaught exception and deduce what the node_module path is and use that snippet.
"mac": {
"category": "public.app-category.productivity",
"target": [
"mas",
"mas-dev"
],
"hardenedRuntime": true,
"entitlements": "build/entitlements-sandbox.plist",
"entitlementsInherit": "build/entitlements-inherit.plist",
"gatekeeperAssess": false,
"asarUnpack": [
"node_modules/node-apple-receipt-verify",
"node_modules/@sentry/electron",
"node_modules/chokidar",
"node_modules/electron-devtools-installer",
"node_modules/fabric",
"node_modules/font-manager",
"node_modules/json-url",
"node_modules/mqtt",
"node_modules/node-machine-id",
"node_modules/printer",
"node_modules/regedit",
"node_modules/usb"
]
},
"afterSign": "build/notarize.js",
"mas": {
"provisioningProfile": "build/embeddedyesmas.provisionprofile"
},
Interestingly, I didn't catch all of the errors this way. On one, my "Helper" process was crashing due to "code signing" issues and a few minutes later I received an email from my Sentry account saying that another dlopen error occurred. This happened without seeing a popup from the main process. I'm assuming it's because the renderer process created the exception... Here's a screenshot for reference:
For some reason, I still have to resign my app using a different plist using this command:
codesign --sign BEEF --force --options runtime --entitlements build/entitlements-mas-auto.plist release/mas-dev/Label\ LIVE.app/
Here's the entitlements-mas-auto.plist:
<?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.application-identifier</key>
<string>7N.com.semireg.LabelLIVE</string>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>7N.com.semireg.LabelLIVE</string>
</array>
<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.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.disable-executable-page-protection</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.device.usb</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.print</key>
<true/>
</dict>
</plist>
I've got every entitlement I could find in there... for testing. It's worth noting that the offending line that causes my app to not launch is:
<key>com.apple.developer.team-identifier</key>
<string>7N</string>
If I include this (which is the default that electron-builder adds), then my app has code signing launch issues.
All this said, I'm stuck with a build that runs but creates blank/white BrowserWindows. This seems to be a known/unsolved issue. https://github.com/electron/electron-osx-sign/issues/188
From my perspective it looks like we're converging on a single issue. Sandbox + hardenedRuntime causes BrowserWindow to silently fail with a blank screen. No crash report, no debug output, no dev tools.
I'm running electron 4.2.11, electron-builder 21.2.0. It's worth noting that I tried upgrading to electron 5/6 but I have too many native module dependencies that don't yet support node 12 (https://github.com/electron/node) and I'm not great with nan, C++, etc.
One final note that's tangential to everything. When I started this morning and ran DEBUG=electron-builder npm run package-mas-dev
the output was very helpful. Between then and now, my debug output has changed to look a lot less helpful:
• exited command=app-builder code=0 pid=60244 out=[{"com.apple.security.app-sandbox":true (long JSON payload)
What could have caused this change? I did uninstall/reinstall node via nvm, removed a bunch of global npm modules. If anyone has an idea I'm very curious to know.
Thanks, everybody.
Thanks for all the details, it's really useful. For info, I managed to upload my app to the mac app store. For this, I didn't need hardenedRuntime, gatekeeperAssess and notarizing (I do the notarization later). I figured out after disabling these 3 elements that my plist could be much simpler. For my app, it worked with this:
<?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>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.application-identifier</key>
<string>TEAM_ID.APP_ID</string>
<key>com.apple.developer.team-identifier</key>
<string>TEAM_ID</string>
<key>com.apple.security.application-groups</key>
<array>
<string>TEAM_ID.APP_ID</string>
</array>
</dict>
</plist>
To avoid the problem with the binary info.plist, I did the packaging/rebranding manually by following https://electronjs.org/docs/tutorial/application-distribution and copying the asar file electron-builder generated. It might be useless though but I did it to understand what's going on and keep my sanity against this binary stuff.
Then I run this signing script manually:
const sign = require('electron-osx-sign');
const path = require('path');
const notarizing = require('./notarize');
const projectPath = `YOUR_PROJECT_PATH`;
const appPath = `${projectPath}/dist_electron_manual/YOUR_APP.app`;
const pkgPath = `${projectPath}/dist_electron_manual/YOUR_APP.pkg`
const platform = `mas`;
const dev = false;
const PARENT_PLIST_PATH = `${projectPath}/entitlements/default.entitlements.mas.plist`;
const PROVISIONING_PROFILE = `${projectPath}/ignore_env/App_store.provisionprofile`
const PROVISIONING_DEV_PROFILE = `${projectPath}/ignore_env/Development.provisionprofile`;
const signApp = () => {
const signOpts = {
app: appPath,
platform,
hardenedRuntime: false,
'gatekeeper-assess': false,
strict: false,
binaries: [
path.join(appPath, './Contents/Resources/app.asar.unpacked/.../YOUR_LIB'),
],
};
if (platform === 'mas') {
signOpts.entitlements = PARENT_PLIST_PATH;
}
if (platform === 'mas' && !dev) {
signOpts['provisioning-profile'] = PROVISIONING_PROFILE;
signOpts.type = 'distribution';
} else {
signOpts['provisioning-profile'] = PROVISIONING_DEV_PROFILE;
signOpts.type = 'development';
}
const flatOpts = {
app: appPath,
platform,
hardenedRuntime: true,
strict: false,
pkg: pkgPath
};
let signProm = sign.signAsync(signOpts);
if (platform === 'mas' && !dev) {
signProm = signProm.then(() => sign.flatAsync(flatOpts))
}
return signProm.then(() => {
console.log('Mac: Signed app.');
if (platform === 'mas' && !dev) {
notarizing.default({
appPath,
electronPlatformName: platform,
});
}
});
};
signApp();
Then I run this upload script:
#!/bin/bash
CURRENT_PATH="$( cd "$(dirname "$0")/.." ; pwd -P )"
echo $CURRENT_PATH
# Name of your app.
APP="APP_NAME"
APP_STORE_USERNAME="[email protected]"
# The path to the location you want to put the signed package.
IPA_PATH="$CURRENT_PATH/dist_electron_manual/$APP.pkg"
echo "Validating the app..."
xcrun altool --validate-app --file "$IPA_PATH" --username "$APP_STORE_USERNAME" --password @keychain:"Application Loader: $APP_STORE_USERNAME"
if [[ $? -ne 0 ]] ; then
exit 1
fi
echo "Uploading the app..."
xcrun altool --upload-app --file "$IPA_PATH" --username "$APP_STORE_USERNAME" --password @keychain:"Application Loader: $APP_STORE_USERNAME"
I have no idea for your last question about the less helpful output, sorry.
I've made more progress. Getting closer... some interesting tidbits here.
I decided to redo my search of the blank/white screen issue by focusing more on sandboxing causing the issue (vs. hardened runtime). That led to this comment where the recommendation is to remove entitlementsInherit. https://github.com/electron/electron-osx-sign/issues/151#issuecomment-331096044
I removed entitlementsInherit and something strange happened inside the auto-generated entitlements file. It added both my personal developer team ID "LX" and my MAS team ID "7N" (again, these are abbreviated).
<key>com.apple.application-identifier</key>
<string>7N.com.semireg.LabelLIVE</string>
<key>com.apple.developer.team-identifier</key>
<string>LX</string>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>7N.com.semireg.LabelLIVE</string>
<string>LX.com.semireg.LabelLIVE</string>
</array>
Note, to view/edit the newly generated entitlements I ran:
codesign --display --entitlements :- release/mas-dev/Label\ LIVE.app/ > auto-entitlements.plist
plutil -convert xml1 auto-entitlements.plist
When I saw this, the first thing I did was try to run the app as-is. It wouldn't launch. To get it to launch I still needed to remove the team-identifier key/string and resign:
codesign --sign BEEF --force --options runtime --entitlements auto-entitlements.plist release/mas-dev/Label\ LIVE.app/
But once I did this... wow, it works. Sandboxed and hardened runtime. 😮
And best of all it seems to run fine on Catalina.
There's still some work to do. I haven't submitted to MAS, yet... but I'm hopeful.
Uploading the latest build to MAS using xcrun altool
returned errors.
App sandbox not enabled. The following executables must include the \"com.apple.security.app-sandbox\" entitlement with a Boolean value of true in the entitlements property list:
[( \"com.semireg.LabelLIVE.pkg/Payload/Label LIVE.app/Contents/Frameworks/Label LIVE Helper.app/Contents/MacOS/Label LIVE Helper\",
\"com.semireg.LabelLIVE.pkg/Payload/Label LIVE.app/Contents/Library/LoginItems/Label LIVE Login Helper.app/Contents/MacOS/Label LIVE Login Helper\",
\"com.semireg.LabelLIVE.pkg/Payload/Label LIVE.app/Contents/Resources/app.asar.unpacked/node_modules/node-apple-receipt-verify/bin/checkreceipt\"
Here's the entitlements for all the above mentioned binaries:
<?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.cs.allow-unsigned-executable-memory</key>
<true/>
<!-- https://github.com/electron-userland/electron-builder/issues/3940 -->
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
Well, yep.
I've tried a whole mess of different entitlementsInherit but none seem to work. They all result in a blank/white BrowserWindow. I've tried the default inherit, doesn't work:
<?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>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
I've even tried using the same plist as what I'm resigning with (dual application-groups). No dice. Gah... I'm running out of ideas.
Alright, I just set hardenedRuntime to false. The app built with entitlements:
<?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>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.device.usb</key>
<true/>
<key>com.apple.security.print</key>
<true/>
</dict>
</plist>
entitlementsInherit:
<?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>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
The mas-dev build runs on Mojave and Catalina. May the MAS reviewers look down on me with good fortune...
In the meantime, hardenedRuntime should be renamed challengedRuntime.
I submitted a build with "hardenedRuntime": false
earlier today along with some of the asarUnpack
suggestions that @semireg posted earlier. Waiting for apple review.
Did I miss the memo that said sandbox + hardenedRuntime is impossible? 😆
hardenedRuntime
is not required for MAS?
@patrickmichalina I was not using hardenedRuntime with mas on Mojave, so figured I would try it again here for Catalina support.
The official apple docs do not discourage hardenedRuntime, so after jumping through the hoops to distribute outside of the App Store (www.label.live/download), I also figured it wouldn't hurt to support both, especially on Catalina. Oh how wrong I was... scars to prove it.
It was/is especially concerning since the errors I saw with dlopen were not new, and were fixable in Mojave by enabling the correct hardenedRuntime entitlements (and maybe webpack externals), but this wasn't enough for Catalina.
Equally possible is my recollection has been corrupted by way too many troubleshooting attempts. I'll be the first to admit that I have next to zero knowledge on the intricacies of dynamic libraries, why they get unpacked to a temp location in /var/folders/... and god knows why they need to be asarUnpacked now, but were somehow fine on Mojave.
One thing I wanted to mention that isn't 100% related to this issue, but will certainly crop up to distributing Electron apps outside the App Store. If you distribute a zipped up .app like I do, Catalina users using Chrome will complain that "the application can't be opened."
The reason seems to be Chrome + Apple's Archive Utility. The resulting decompressed file is somehow corrupt.
The solution is to download using Safari, where the decompression seems to happen within Safari itself, rendering a good .app bundle.
I've seen a lot of other issues surrounding this, but never this one, or the others that have @semireg has been posting in. I've been banging away at this for close to 2 weeks, with 5 or 6 failed app store submissions, but day 1 had a DMG version working in Catalina, electron 6/hardened runtime/notarized. I don't think I'm any further along than anyone in this thread, but figured I'd post some of my findings to see if anybody sees anything intriguing:
I went back to electron 5 for the time being. Electron 6 adds a login helper (and other helpers) that just seems to be another entitlements hurdle to jump, plus you need to manually adjust your node_module with this accepted PR.
The binary plist thing seemed like a surefire issue, but as far as I could tell it was a red herring. Switching to electron-packager
got rid of binary plists, but no errors have been different.
I've switched from electron-builder
to electron-packager
, electron-osx-notarize
, and electron-osx-flat
, at least for now. I don't think this has gotten me any further, but I at least feel like I have a bit more control (I probably don't).
All the blog posts and "working" solutions I've found always end up being for direct download situations. One point of contention I found is that all directions online, and even electron-packager
's built-in notarize, will only notarize the .app
file and not the .pkg
file. At this point, I'm allowing it to notarize that, then converting to pkg, then notarizing THAT as well. Love the significantly longer built process notarization causes, not to mention the notarization system had an outage last week. Only my latest build had this last point in it, and it was just rejected about 15 minutes ago with the dlopen
issue, which I've been seeing this whole time. I had been seeing a "you didn't notarize" issue prior to this, so it was at least a step in the right direction.
I guess my next step is to disable hardenedRuntime, as you've mentioned above, and try again. My last two submissions took 50 hours and 24 hours to get rejected, so I may as well start the long wait.
Edit: Also throwing my only native module (keytar
) into asar unpacked, so with these two changes I'm already feeling far too optimistic.
@james-criscuolo As far as I know, notarization is not needed for mas builds. At least I have never notarized them.
This documentation page has a note:
Important
Beginning in macOS 10.14.5, all new or updated kernel extensions and all software from developers new to distributing with Developer ID must be notarized in order to run. Beginning in macOS 10.15, notarization is required by default for all software.
I _hope_ that this is the only new requirement right now, which has put all of us in this mess. Hardened runtime was also introduced, but I think we have a bit longer on that one. If anybody has seen anything saying otherwise, or knows of some 3rd variable that is now a requirement, please let me know, it's been very difficult to find a central place explaining the new additions and what's required.
I just got rejected from my last attempt but... only one error screenshot was attached to the rejection.
In all past rejections they have included two screenshots: 1) this "developer cannot be verified" and 2) the infamous dlopen JavaScript error.
I asked MAS reviewers if the app launched successfully after this error... waiting to hear back. I suspect it does launch. My Catalina box reproduces the error above using the mas-dev build and the app launches. I just chalked up this error to mas-dev and quarantine via AirDrop... but I guess it's a "real" issue as far as MAS review is concerned.
(Edit: Note, my notarized "mac" builds run perfectly on Catalina!)
I submitted this build without notarization. Just now I notarized my mas-dev build, AirDropped to my Catalina box and I'm still getting the same "developer cannot be verified" error for whatever temporary SNAFU file is created.
What in the world do we do now? I really need to better understand what process is at work (pun intended) when the app/system are trying to run an executable (presumably the Helper/Chromium instance) from a temporary file.
I used this article (linked in electron builder's docs) to get my notarization working. The piece missing is that the article is for a DMG, so there are a few leaps to make, including notarizing the pkg as well. I will caution that I also do not have a working app store build yet either.
My last rejection is the opposite of yours, I had been getting two screenshots, but only got the dlopen one after sorting out my notarization (hopefully). Hoping the build that has been waiting for review since last night passes, its been in review for about 3 hours.
Your app crashed on Mac running macOS 10.15 when we:
-launch the app
No crash log was generated by this crash.
This is all the info they had for me. Now I really don't know where to go from here
I wonder if what we're seeing is “Gatekeeper Path Randomization” (GPR) as described here: https://weblog.rogueamoeba.com/2016/06/29/sierra-and-gatekeeper-path-randomization/
Searching GitHub:
Nothing I read mentioned electron dylibs failing developer signing (or notarization?) at startup. I have another hunch, unanchored to any particular troubleshooting, that makes me think this is related to the electron.asar. But why is only Catalina affected? Very frustrating.
@james-criscuolo, do you have a working mas-dev build? I found that to be the best path to sane troubleshooting. Otherwise it's just publish and pray.
In case it helps anyone, I am 99% sure that you don't need to notarize for a MAS submission. We recently got our self-distributed .zip build working on Catalina via electron-builder 21.2.0 + Electron 5.0.3 + electron-notarize 0.1.1. We are still struggling with a new-to-the-app-store MAS build, though we have gotten it to the point that it doesn't crash, but it does give the "macOS cannot verify that this app is free from malware" warning on Catalina.
To avoid MAS builds crashing we had to:
mas
specifically and let mac
be set to true`)The other thing that was a revelation for us, is that you CAN test your PKG built via target: mas
(not mas-dev) by "installing" it via sudo installer -store -pkg path/to/your.pkg -target /
after build. Right now it works great on 10.14.6. I have a hunch that Catalina requires a build from Electron 6 and not 5, and I am concerned that there hasn't been an electron-builder release in 3 months.
@alibosworth, thank you for the note. If I understand your situation, it makes me feel better that you and I are in the same relative place.
My app is using the latest Electron 4, and like I mentioned above, our self-distributed .zip build ("mac") is not affected by the "macOS cannot verify that this app is free from malware" error. That leads me to believe we're dealing with a bug in Catalina or electron-builder.
@semireg yeah, I think a lot of people are struggling with this. We've been working on it on and off for months.
I'm not sure about "mas" (sandboxed) build on Mojave ✅
because I'm building it on on Mojave, and the installed PKG (via installer -store -pkg ....
) does work on Mojave, if I try the same on a Catalina machine I get the "cannot verify that this app is free from malware", which is what the MAS reviewer reports, so at least I'm glad I can repro what they are seeing (for a long time I was under the impression that I couldn't actually test the PKG I was building to submit).
I wonder if we need to log a MAS build / Catalina specific issue, I feel like things are a bit confusing given that this topic is named specifically around the hardenedRuntime option.
@alibosworth Have you been able to get an un-notarized app into the app store? I posted their documentation above, and I'm fairly certain the "free from malware" thing directly translates to "not notarized," but if there is a reason to believe we don't have to notarize, then I will drop that from my attempts.
Thank you so much for posting the sudo installer
line, that will be tremendously helpful in attempting to make this work. I'm going to try going back to electron-builder
, as I've never had a working pkg from electron-packager
and see where I can get from there.
@james-criscuolo No, we haven't been able to, however, about the quote you posted above:
Beginning in macOS 10.14.5, all new or updated kernel extensions and all software from developers new to distributing with Developer ID must be notarized in order to run. Beginning in macOS 10.15, notarization is required by default for all software.
Note that this refers to "distributing with Developer ID" specifically refers to non-MAS distribution:
For software and applications that are downloaded from places other than the Mac App Store, developers can get a Developer ID certificate and submit their software for notarization by Apple.
It would be really nice if they clarified the documentation around this because it certainly isn't clear, but I am fairly sure that Notarization isn't required for MAS builds, because they go through a more thorough and manual process before they are available to users.
The other thing that has been helpful for me is this app that exposes a lot more info about your build https://brockerhoff.net/RB/AppCheckerLite/
I just got an email notification that my app was finally accepted. I’ll post details soon, but it was not notarized and is not using hardened runtime.
For those curious, I think my crash was related to having the hardened runtime entitlements present, while setting hardenedRuntime to false.
I'm still extremely tempted to notarize, despite hearing a success without it, it's this "free from malware" thing that I'm worried about. While it may not be necessary, my thought is that it would cover that one.
As mentioned above, our app was just accepted in the Mac App Store as working on Catalina. In the past, we have never used hardened runtime or notarized the mas
build of our app. That was reserved for the dmg
build distributed on our website. That turned out to still be true here. As previously highlighted, trying to use hardened runtime with mas
builds results in a blank white renderer page for whatever reason.
In the end, the problem that was causing the "____ can’t be opened because its integrity cannot be verified." followed by the dlopen
error was that we needed to asarUnpack
the native node modules that we were using. In our case, this was desktop-idle
and keytar
. Once I _properly_ added that, the app passed review.
electron-builder --mac mas -p never
...
"mas": {
"entitlements": "resources/entitlements.mas.plist",
"entitlementsInherit": "resources/entitlements.mas.inherit.plist",
"hardenedRuntime": false,
"asarUnpack": [
"node_modules/desktop-idle",
"node_modules/keytar"
]
},
...
For reference, we have been tracking this issue on our repo here: https://github.com/bitwarden/desktop/issues/320
The final working pieces of our build can be found here:
https://github.com/bitwarden/desktop/blob/master/package.json#L63
https://github.com/bitwarden/desktop/blob/master/scripts/after-sign.js
https://github.com/bitwarden/desktop/blob/master/resources/entitlements.mas.plist
https://github.com/bitwarden/desktop/blob/master/resources/entitlements.mas.inherit.plist
Hope this helps!
Fwiw, here's a screenshot from RB App Checker Lite (great app, btw) comparing two MAS app bundles directly downloaded from the App Store. The left side is BitWarden's successful Catalina MAS build. The right side is Label LIVE's currently broken MAS build from the App Store.
Note that there are no red flags on the Label LIVE build.
My notarized build does at least load for the app store reviewers, they are now claiming I've given them a bad username and password. This could be an entitlements issues, but I've seen them typo this and blame me before, so I'm not ready to investigate further yet. Regardless, it looks like a notarized build will at least load for them. Still can't say whether it helped at all, but a promising advancement at least. To reiterate from @kspearrin, I think the other big difference is adding all native modules to the asarUnpack section. Entitlements should likely remain untouched from your previous working MAS build.
So I've been having similar issues. Specifically when I submitted to the app store we were told the app crashed in versions of 10.14 I was able to fix that by adding
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
to both my parent and child entitlements but then I got the white screen on any OSX below 10.14.
The magic combo for me was to set hardened runtime to false and remove that entitlement from the child entitlements (with the hardened runtime it only worked if it was in both files). Still some testing to do, but so far it seems to run on all OSs.
@kspearrin thank you very much for sharing. I tried the exact same settings that you are using for bitwarden, but with no luck. When installing via sudo installer -store -pkg path/to/your.pkg -target /
(as suggested by @alibosworth) the app crashes right away. No logs, no error. Just an empty white window opening up for half a second (which i can only see if I focus it by hammering on the app icon).
May I ask if you are you able to install your app with the installer command and run it?
I also see that you are using electron 5. Is this correct?
https://github.com/johannesjo/super-productivity
electron-builder: 21.2.0 / 21.1.5
electron: 6.0.12 / 5.0.11
os: mac os mojave 10.14.6
Note: I also should add that the signed dmg is running fine. Only mas and mas dev are not working at all.
@johannesjo, can you edit your comment to include what OS you're trying to install on and what electron/electron-builder version you're using?
@johannesjo
$ sudo installer -store -pkg Bitwarden-1.16.10.pkg -target /
installer: Note: running installer as an admin user (instead of root) gives better Mac App Store fidelity
installer: Bitwarden-1.16.10.pkg has valid signature for submission: 3rd Party Mac Developer Installer: 8bit Solutions LLC (LTZ2PFU5D6)
installer: Installation Check: Passed
installer: Volume Check: Passed
installer: Bundle com.bitwarden.desktop will be relocated to /Users/me/bitwarden/desktop/dist/mas/Bitwarden.app
installer: Starting install
installer: Install 0.0% complete
installer: Install 7.2% complete
installer: Install 16.5% complete
installer: Install 32.7% complete
installer: Install 41.9% complete
installer: Install 64.2% complete
installer: Install 100.0% complete
installer: Finished install
Running the .app
after that works.
@semireg I added the info.
to both my parent and child entitlements but then I got the white screen on any OSX below 10.14.
The magic combo for me was to set hardened runtime to false and remove that entitlement from the child entitlements (with the hardened runtime it only worked if it was in both files). Still some testing to do, but so far it seems to run on all OSs.
@alexistbell I remember that notarize you app need to set hardened runtime to true and add the entitlement com.apple.security.cs.allow-unsigned-executable-memory
, how do do successfully notarize you app when set hardened runtime to false?
@Jocs The notarizing tool logged a warning: The executable does not have the hardened runtime enabled
when hardenedRuntime
was set to false
but the notarization still finished successful.
Alright folks, I finally cracked the situation wide open and learned what was happening. I haven't submitted to MAS yet, but the "developer cannot be verified" error is gone on Catalina. 🙌
TLDR: Ran strings
on dynamically created executable and realized it was FSEvents native module. Reinstalled fs-jetpack to correct app/package.json.
I solved it by opening a developer ticket with Apple. A great engineer walked me through what they saw. They asked, "Can you explain to me who is creating (or downloading) this .7NB4X9P2DR.com.semireg.LabelLIVE.x38El1
Mach-O 64-bit bundle x86_64 file?"
No, I couldn't... but I started looking in the temp folder and found a whole mess of those randomly created files.
$ ls -al ./v4/7rtxrf3s3jqf9jgvz51q6g1m0000gn/T/com.semireg.LabelLIVE/
total 800
drwx------@ 14 caylan staff 448 Oct 17 10:27 .
drwx------ 281 caylan staff 8992 Oct 17 03:35 ..
-rwxr-xr-x@ 1 caylan staff 38304 Oct 16 11:28 .7NB4X9P2DR.com.semireg.LabelLIVE.8OxAQB
-rwxr-xr-x@ 1 caylan staff 38304 Oct 17 10:27 .7NB4X9P2DR.com.semireg.LabelLIVE.Nhd9Wg
-rwxr-xr-x@ 1 caylan staff 38272 Oct 13 11:38 .7NB4X9P2DR.com.semireg.LabelLIVE.Og2e5L
-rwxr-xr-x@ 1 caylan staff 38304 Oct 14 13:46 .LXWE49S3J9.com.semireg.LabelLIVE.1pnW74
-rwxr-xr-x@ 1 caylan staff 38304 Oct 15 15:10 .LXWE49S3J9.com.semireg.LabelLIVE.3VqHgP
-rwxr-xr-x@ 1 caylan staff 38304 Oct 14 13:32 .LXWE49S3J9.com.semireg.LabelLIVE.5Rw75x
-rwxr-xr-x@ 1 caylan staff 38304 Oct 15 15:02 .LXWE49S3J9.com.semireg.LabelLIVE.HOZhm2
-rwxr-xr-x@ 1 caylan staff 38304 Oct 14 09:51 .LXWE49S3J9.com.semireg.LabelLIVE.e3nB30
-rwxr-xr-x@ 1 caylan staff 38272 Oct 13 12:08 .LXWE49S3J9.com.semireg.LabelLIVE.l5BwcK
-rwxr-xr-x@ 1 caylan staff 38304 Oct 14 13:43 .LXWE49S3J9.com.semireg.LabelLIVE.xw0D9J
I searched my application bundle for a file of similar size or exact md5 and came up empty. The file is definitely being dynamically created…
I ran strings on it, and doh...
I ran strings on it. Interesting results…
$ strings .7NB4X9P2DR.com.semireg.LabelLIVE.Nhd9Wg
fsevents:FSEvents
handler
FSEvents
start
stop
Constants
~ObjectWrap
../../nan/nan_object_wrap.h
persistent().IsNearDeath()
Utf8String
../../nan/nan.h
len <= INT_MAX
str_ != 0
Wrap
persistent().IsEmpty()
object->InternalFieldCount() > 0
WeakCallback
wrap->refs_ == 0
wrap->handle_.IsNearDeath()
kFSEventStreamEventFlagNone
.........
kFSEventStreamEventFlagItemIsSymlink
../fsevents.cc
!persistent().IsEmpty()
Unref
!persistent().IsWeak()
refs_ > 0
Unwrap
This is a native node module related to filesystem events.
When I first started my project last year I used https://github.com/electron-react-boilerplate/electron-react-boilerplate which, at the time, used a 2 package.json system where native modules are installed to app/package.json, and all other non-native modules are installed to the top-level package.json (TLP).
If you accidentally add a native module to the TLP it will probably work in development, but come packaging you are in for cryptic errors.
This one takes the cake. I had fs-jetpack
installed in my top-level package.json, causing the FSEvents' Mach-O 64-bit bundle x86_64 file to be dynamically extracted from the ASAR. This causes grief with 10.15, and thus the "developer cannot be verified" error.
I uninstalled fs-jetpack
from the top-level, re-installed into app/package.json, added the appropriate declarations to my top-level package.json (asarUnpack) and now the mas-dev build runs on Catalina without an error.
@semireg that is really interesting.
What do you mean by this:
added the appropriate declarations to my top-level package.json
So the generalized process for tracking this down, in theory, is to note the name of the process that errors on Catalina (does the name change between computers?), locate it in the temp dir, and check its strings to try and figure out which dep it might be? Then make sure it isn't being pulled in via the main package.json?
@alibosworth, edited for clarity (asarUnpack
)
The process is generally:
• Note the name of the file that is failing the developer check
• Search for that file: find /var/folders -name FILENAME
• List the strings of the file: strings FILEPATH
Thanks, I haven't used asarUnpack before, but the docs say:
Node modules, that must be unpacked, will be detected automatically, you don’t need to explicitly set asarUnpack - please file an issue if this doesn’t work.
so in theory is this a bug somewhere (in electron/builder) rather than just a config issue?
@Jocs So my notarization finished successfully. Still waiting on review from Apple, so there's always a potential for issues to come up there however here's what I'm doing in case it helps. My parent-entitlements file:
<?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>
<true/>
<key>com.apple.security.device.bluetooth</key>
<true/>
<key>com.apple.security.device.camera</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>
I'm using electron-packager, but then I manually call both electron-osx-sign
and electron-notarize
because I found that's the best way to make sure the custome Framework in my app gets signed as well. Here's the relevant parts of my build script:
if (platform === 'mac') {
const binaryPath = path.join(appPath, 'Contents/Frameworks/Core.framework');
const options = {
entitlements: path.join(__dirname, '../signing/mac/parent-entitlements.plist'),
'entitlements-inherit': path.join(__dirname, '../signing/mac/child-entitlements.plist'),
identity: signingOptions.type === 'distribution' ? '3rd Party Mac Developer Application: xxxx' : 'Mac Developer: xxx',
'provisioning-profile': signingOptions.profile,
hardenedRuntime: false,
app: appPath,
binaries: [binaryPath],
'gatekeeper-assess': false
};
osxSign(options, err => {
if (err) reject(err);
else resolve();
});
and for notarization:
if (platform === 'mac') {
const options = {
appBundleId: Defines[platform].appBundleId,
appPath,
appleId,
appleIdPassword: password
};
notarize(options, err => {
if (err) reject(new Error(err));
else resolve();
});
It could be a bug, but it's entirely possible that the users here relying on asarUnpack have somehow inadvertently included a native module into their ASARs somehow. I don't know. My brain feels like it's melted the last two weeks. Nothing is real any more...
I just received an automated email from App Store Connect:
ITMS-90238: Invalid Signature - The executable at path Label LIVE.app/Contents/Resources/app.asar.unpacked/node_modules/fsevents/build/Release/.node has following signing error(s): code object is not signed at all In architecture: x86_64 .
Refer to the Code Signing and Application Sandboxing Guide at http://developer.apple.com/library/mac/#documentation/Security/Conceptual/CodeSigningGuide/AboutCS/AboutCS.html and Technical Note 2206 at https://developer.apple.com/library/mac/technotes/tn2206/_index.html for more information.
It never ends.
Here was my asarUnpack previous to being rejected:
"node_modules/fsevents",
"node_modules/fs-jetpack",
I just opted to put fsevents in there to be safe, but maybe there's some automatic way that electron-builder pulls in fs-jetpack's dependencies, and adding it here manually stopped it from getting signed? So, I removed fsevents line and tried packaging a mas-dev. Nope. fsevents wasn't included and caused the same "developer cannot be verified" issue.
I kept my asarUnpack the same (both fsevents and fs-jetpack) and instead added a mas.binaries declaration:
"binaries": ["release/mas/Label LIVE.app/Contents/Resources/app.asar.unpacked/node_modules/fsevents/build/Release/.node"]
$ codesign -vvv --deep --strict release/mas/Label\ LIVE.app/Contents/Resources/app.asar.unpacked/node_modules/fsevents/build/Release/.node
release/mas/Label LIVE.app/Contents/Resources/app.asar.unpacked/node_modules/fsevents/build/Release/.node: valid on disk
release/mas/Label LIVE.app/Contents/Resources/app.asar.unpacked/node_modules/fsevents/build/Release/.node: satisfies its Designated Requirement
An improvement. Now to submit again...
@alexistbell are you using dgram
UDP sockets by chance? I see you added the network entitlements. I am finally able to run the Catalina sandbox builds locally with app-sandbox
by turning off hardenRuntime
, but the UDP socket fails to connect in a sandboxed app. Is node dgram
considered a raw socket
according to apples sandbox guidelines?
apple docs: Circumstances Requiring Elevated Privileges
Circumstances Requiring Elevated Privileges
Regardless of whether a user is logged in as an administrator, a program might have to obtain administrative or root privileges in order to accomplish a task. Examples of tasks that require elevated privileges include:
- manipulating file permissions, ownership
- creating, reading, updating, or deleting system and user files
- opening privileged ports (those with port numbers less than 1024) for TCP and UDP connections
- opening raw sockets << **(is a node dgram considered raw?)**
- managing processes
- reading the contents of virtual memory
- changing system settings
- loading kernel extensions
Edit: I got this working. I had a typo in the entitlement com.apple.security.device.client
instead of com.apple.security.network.client
@patrickmichalina I checked and no we aren't using UDP. The network entitlements predate my time on the project, so I'm not sure of exactly what circumstance caused them to be added. Sorry I can't be of more help on that one.
Alright y'all, my app (Label LIVE) was finally approved by Apple. 🍻
@semireg Congrats! You're using electron 4 right? Would be cool if you could share the config that did the trick with the rest of us! :)
"mac": {
"category": "public.app-category.productivity",
"hardenedRuntime": true,
"entitlements": "build/entitlements-lll.plist",
"entitlementsInherit": "build/entitlements-lll.plist",
"gatekeeperAssess": false,
"asarUnpack": [
"*.node",
"node_modules/node-apple-receipt-verify",
"node_modules/@sentry/electron",
"node_modules/chokidar",
"node_modules/electron-devtools-installer",
"node_modules/fabric",
"node_modules/fsevents",
"node_modules/fs-jetpack",
"node_modules/font-manager",
"node_modules/json-url",
"node_modules/mqtt",
"node_modules/node-machine-id",
"node_modules/printer",
"node_modules/regedit",
"node_modules/usb"
]
},
"mas": {
"hardenedRuntime": false,
"provisioningProfile": "build/embeddedyesmas.provisionprofile",
"entitlements": "build/entitlements-sandbox.plist",
"entitlementsInherit": "build/entitlements-inherit.plist",
"binaries": ["release/mas/Label LIVE.app/Contents/Resources/app.asar.unpacked/node_modules/fsevents/build/Release/.node"]
},
entitlements-sandbox.plist
<?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>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.device.usb</key>
<true/>
<key>com.apple.security.print</key>
<true/>
</dict>
</plist>
entitlements-inherit.plist
<?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>
<true/>
<key>com.apple.security.inherit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
I am unsure if the last two "security.cs" properties are required. I remember reading in docs that the "security.inherit" property must only exist as a sibling to app-sandbox... but, here we are... 😄 When I submit my next maintenance build I'll start paring these back to remove any non-essential properties.
@semireg I'm having trouble finding the dynamically generated sub-application that triggers the "___ cannot be opened because the developer cannot be verified" warning... Where did you find it?
Try a find /var/folders | grep -i BUNDLEID
to get an idea of where to look. It’s probably buried 4 directories deep. You may also want to check console.app for absolute paths that trigger these warnings. Use a unique portion of your BUNDLEID as a search filter.
@semireg man you saved me! Your investigation totally makes sense. I was struggling with notarization for a few days and it's completely wrong. Today I've passed the review.
I'm able to confirm you don't need notarization for MAS. Ensure that if you have native modules you have to unpack them from asar. If you sign your application the "developer cant be verified" problem on Catalina related only to dynamically unpacking modules.
Yes thanks again @semireg, like @klen above we also passed review today thanks to your leads.
The problem for us was electron-spellchecker
and including it in asarUnpack
was part of the fix, although we also had to include node_modules/@felixrieseberg/spellchecker
there as well.
Tips for anyone else on this same issue:
hardenedRuntime: false
, and had a provisioningProfile
definedELECTRON_BUILDER_CONFIG
env var, the asarUnpack
in our package.json was ignored so we had to define it in the config-specific JSON file. Check the generated builder-effective-config.yaml to see what options EB is _really_ using. (It may be a bug that the configs aren't merged)find /private/var/folders -name [cryptic filename from warning]
strings [full path to resulting file]
mdfind "[unique string]" -onlyin ./app/node_modules
I'm relieved we have work-arounds in place - and nervous that the main devs like @develar and @stefanjudis have been missing in this process.
I suggest everyone donate money to this project so we can get the most experienced developers involved in these recent issues.
https://www.electron.build/donate
Make it rain! 💰💰💰
Note that publishing Electron apps to the Windows 10S store (as well as Mac App Store on Catalina, if I understand correctly) requires keeping native NodeJS plugins outside of app.asar
, due to the security policy (i.e. signed executables / dynamic libraries).
I have been using this electron-builder
directive to ensure that all native modules (regardless of their "owner" NPM package) are deployed into the app.asar.unpacked
folder as standalone files (which would otherwise be extracted into temporary folders at runtime, thus the security breach):
"asarUnpack": [
"**/*.node"
],
I finally got it working. My debugging efforts were seriously confused by this bug: https://github.com/electron/electron/issues/9985
So take care to comment out app.makeSingleInstance()
in case your trying to debug this.
@johannesjo amazing! thank you, the singleApp fix allowed me to build a mas-dev application and have it launch! This was the problem haha but now the app just shows blank white screen.. Time to debug this problem now :joy:
Awesome! Im happy to report we've solved _all_ the build problems that we've been experiencing. Thank you @johannesjo, this was the issue driving us up a wall :joy:
"mac": {
"category": "public.app-category.productivity",
"icon": "./assets/icons/icon.icns",
"asarUnpack": [
"**/*.node"
],
"entitlements": "mac.plist",
"entitlementsInherit": "mac.plist",
"aftersign": "notarize.js",
"gatekeeperAssess": false
},
"mas": {
"provisioningProfile": "./embedded.prod.provisionprofile",
"entitlements": "./entitlements.mas.plist",
"entitlementsInherit": "./entitlements.mas.inherit.plist",
"hardenedRuntime": false,
"provisionProfile": "YOURPROVISIONPROFILE"
},
entitlements for mac:
<?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.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>
mac entitlementsInherit is the same as regular mac entitlements
MAS entitlements:
<?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>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.all</key>
<true/>
<key>com.apple.security.application-groups</key>
<string>xxxENTERYOUROWNTHINGHERE</string>
</dict>
</plist>
MAS entitlementsInherit:
<?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>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
We are currently struggling with this issue. Electron 5.0.11 and 6.1.2, electron-builder 22.1.0, macOS Catalina.
package.json:
...
"mac": {
"hardenedRuntime": true,
"gatekeeperAssess": false,
"entitlements": "mac.plist",
"entitlementsInherit": "mac.plist"
},
"afterSign": "resources/notarize.js",
...
mac.plist:
<?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.files.user-selected.read-write</key>
<true/>
<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.network.client</key>
<true/>
</dict>
</plist>
Build is OK, signing is OK, notarizing is OK. Launching the app: crashes with EXC_BAD_ACCESS (Code Signature Invalid). A notarized app without the hardenedRuntime works perfectly fine. What are we doing wrong? Where can be the problem? What direction to look at?
@DominikLevitsky what are you signing you mac app for? Is this standalone version or app store version? Also which certificate are you signing with? Youll need different cert for standalone vs app store builds.
Also for us we have not yet tested with Catalina so try the asarUnpack thing people mentioned above or the way you see it on my config.
@JohnTendik We are signing for mac, standalone, .dmg. We are signing with a certificate that worked flawlessly before Catalina. Also, as I mentioned this same config, with hardenedRuntime: false, works and launches absolutely fine. So I guess the certificate should be fine?
"asarUnpack": [ "**/*.node" ]
Does not help.
Run the crashing app through https://brockerhoff.net/RB/AppCheckerLite/
We had success in pairing down the entitlements (not defining any custom entitlements for MAC build, but we still have some for MAS build)
Further info:
You need at least the following entitlements:
<?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.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/> </dict> </plist>
Further info from https://medium.com/@TwitterArchiveEraser/notarize-electron-apps-7a5f988406db
Make sure to try out starting the app after this process, if some entitlements are missing, the app might be broken after notarization.
really thx !!!! solved my problem!!!!
Does anyone know how to fix the following error -
Error: Failed to upload app to Apples notarization servers
2019-11-09 18:03:49.456 altool[32910:902264]
*** Error: Unable to validate your application.
This Apple ID has been locked for security reasons.
Visit iForgot to reset your account (https://iforgot.apple.com).
I'm trying to notarize my app and distribute on GitHub. I have a valid developer certificate which used to work well but everything is broken on Catalina.
entitlements.mac.plist
<?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.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>
electron-builder: 20.43.0
electron-notarize: 0.1.1
Package.json
"build": {
"afterSign": "scripts/notarize.js",
"asar": true,
"asarUnpack": [
"**/*.node"
],
"files": [
"**/*",
"!docs${/*}",
"!node_modules/@paulcbetts/cld/deps/cld${/*}"
],
"mac": {
"category": "public.app-category.productivity",
"darkModeSupport": true,
"artifactName": "${productName}-${version}-${arch}.${ext}",
"hardenedRuntime": true,
"entitlements": "build/entitlements.mac.plist",
"entitlementsInherit": "build/entitlements.mac.plist",
"gatekeeperAssess": false
},
notarize.js
require('dotenv').config();
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;
return await notarize({
appBundleId: 'my_app_id',
appPath: `${appOutDir}/${appName}.app`,
appleId: process.env.APPLE_ID,
appleIdPassword: process.env.APPLE_ID_PASS,
});
};
@akashnimare that error says your apple developer account has been locked. Are you sure you're using the correct password? It should be an app-specific password you create in the account settings page, after turning on 2-factor auth.
Also, it was mentioned above that for mac notarization you need some more entitlements. Try adding these
<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/>
@JohnTendik thanks a lot for the help. Let me try it. BTW, I need to get the password from here, right? I have 2FA on.
I have tried your fix but the npm run dist
command hangs here for hours -
Failed to upload app to Apples notarization servers
• signing file=dist/mac/Zulip.app identityName=Developer ID Application: Namme, Inc. (XXXXXXXX) identityHash=XXXXXXXXXXXXXXX provisioningProfile=none
electron-builder at processImmediate (timers.js:658:5) +0ms
Error: Failed to upload app to Apples notarization servers
2019-11-11 18:25:18.731 altool[91150:1226453] *** Error: Unable to validate your application. This Apple ID has been locked for security reasons. Visit iForgot to reset your account (https://iforgot.apple.com).
at /Users/myname/dev/work/zulip-desktop/node_modules/electron-notarize/src/index.ts:76:13
at step (/Users/myname/dev/project/zulip-desktop/node_modules/electron-notarize/lib/index.js:31:23)
at Object.next (/Users/myname/dev/project/zulip-desktop/node_modules/electron-notarize/lib/index.js:12:53)
at fulfilled (/Users/myname/dev/project/zulip-desktop/node_modules/electron-notarize/lib/index.js:3:58)
at process._tickCallback (internal/process/next_tick.js:68:7)
From previous event:
at runCallback (timers.js:705:18)
at tryOnImmediate (timers.js:676:5)
at processImmediate (timers.js:658:5)
From previous event:
at MacPackager.doPack (/Users/myname/dev/project/zulip-desktop/node_modules/app-builder-lib/src/platformPackager.ts:167:165)
at /Users/myname/dev/project/zulip-desktop/node_modules/app-builder-lib/src/macPackager.ts:90:63
at Generator.next (<anonymous>)
From previous event:
at MacPackager.pack (/Users/myname/dev/project/zulip-desktop/node_modules/app-builder-lib/src/macPackager.ts:82:95)
at /Users/myname/dev/project/zulip-desktop/node_modules/app-builder-lib/src/packager.ts:430:24
at Generator.next (<anonymous>)
at xfs.stat (/Users/myname/dev/project/zulip-desktop/node_modules/fs-extra/lib/mkdirs/mkdirs.js:56:16)
at callback (/Users/myname/dev/project/zulip-desktop/node_modules/fs-extra/node_modules/graceful-fs/polyfills.js:289:20)
at FSReqWrap.oncomplete (fs.js:154:5)
From previous event:
at Packager.doBuild (/Users/myname/dev/project/zulip-desktop/node_modules/app-builder-lib/src/packager.ts:396:24)
at /Users/myname/dev/project/zulip-desktop/node_modules/app-builder-lib/src/packager.ts:366:57
at Generator.next (<anonymous>)
at /Users/myname/dev/project/zulip-desktop/node_modules/fs-extra/node_modules/graceful-fs/graceful-fs.js:111:16
at /Users/myname/dev/project/zulip-desktop/node_modules/graceful-fs/graceful-fs.js:43:10
at /Users/myname/dev/project/zulip-desktop/node_modules/fs-extra/node_modules/graceful-fs/graceful-fs.js:45:10
at FSReqWrap.args [as oncomplete] (fs.js:140:20)
From previous event:
at Packager._build (/Users/myname/dev/project/zulip-desktop/node_modules/app-builder-lib/src/packager.ts:335:133)
at /Users/myname/dev/project/zulip-desktop/node_modules/app-builder-lib/src/packager.ts:331:23
at Generator.next (<anonymous>)
at runCallback (timers.js:705:18)
at tryOnImmediate (timers.js:676:5)
at processImmediate (timers.js:658:5)
From previous event:
at Packager.build (/Users/myname/dev/project/zulip-desktop/node_modules/app-builder-lib/src/packager.ts:288:14)
at build (/Users/myname/dev/project/zulip-desktop/node_modules/app-builder-lib/src/index.ts:59:28)
at build (/Users/myname/dev/project/zulip-desktop/node_modules/electron-builder/src/builder.ts:228:10)
at then (/Users/myname/dev/project/zulip-desktop/node_modules/electron-builder/src/cli/cli.ts:49:19)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] dist: `tsc && electron-builder`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] dist script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/myname/.npm/_logs/2019-11-11T12_55_18_768Z-debug.log
Even though I'm using the right ID and pass, Apple is not letting me notarize the app.
You need to add you app email and password as environment variables appleId and appleIdPassword
@itsthisjustin is this the same as my appleID/applePassword or something different?
You need to add you app email and password as environment variables appleId and appleIdPassword
@itsthisjustin is this the same as my appleID/applePassword or something different?
Yes but it’s an app password that you have to generate in the account.
@itsthisjustin this one, right -
@akashnimare Yes, correct. "App-specific Passwords" you want to generate one and use that as the applepassword and ur email as the appleId
Okay, thanks. I have tried it but I'm still getting the error -
Error: Failed to upload app to Apples notarization servers
2019-11-11 20:05:20.107 altool[1017:1275185] *** Error: Unable to validate your application.
This Apple ID has been locked for security reasons.
Visit iForgot to reset your account (https://iforgot.apple.com).
My .env
file looks like this -
APPLE_ID: '[email protected]',
APPLE_ID_PASS: 'xxxx-xxx-xxxx-xxxx'
electron-builder: v22.0.1
electronn-notarize: v0.2.0
electron: v3.1.10
node: v10.16.3
Other details here.
Is there any hidden thing I'm missing here. I have spent weeks trying to notarize the app but no luck :/ can you help @JohnTendik, @itsthisjustin?
Here is the app I'm trying to build - https://github.com/zulip/zulip-desktop
@akashnimare my guess is your .env file is not working. Try adding debug=electron-osx-sign and see if the log changes. How are you running your build / notarize ?
Try hard coding the apple id and password inside then notarize js file and see if that fixes it. If so, then you know your env file is not working.
@JohnTendik okay, on your suggestion I hardcoded the appleID and pass into the notarize.js
script and I didn't receive any error. I'm guessing the code-signing + notarization worked well. I just have two questions now -
.env
script? For you, info here is the open PR we are trying - https://github.com/zulip/zulip-desktop/pull/834/filesUpdate - I have received the email from apple so I think the app was successfully notarized. Just need to figure out why .env
is not working. I'm using electron-builder here with npm run dist
to build + notarize the app.
you should receive an email saying the notarization was successful. You can also test it, try to install the app and launch it, if you don't get the malware message than you have notarized successfully.
@akashnimare
Is there any way to know that my app is notarized?
It should be indicated in this tool https://brockerhoff.net/RB/AppCheckerLite/
What could be wrong with the .env script?
An .env file is only useful if you have something configured to read those values and load them as actual Environment Variables. That topic is a general one and has nothing to do with electron-builder or this issue. Electron-builder DOES have its own built-in support for loading EVs from a file however you must name the file electron-builder.env
Please see the docs.
The answer (ish) for us was that hardened runtime (sand boxing) just doesn't work with Electron. We were having the same 'open the app, it fails immediately, watch the crash dump open a minute later' situation. What (mostly) solved it was not hardening it.
Two very useful pieces of software in diagnosing where we were:
But ultimately, nothing worked until we dumped the sand boxing.
So our successful spec is, including notarisation and code signing:
Electron: 6.0.8 or 7.0.1
"electron-builder": "22.1.0"
"electron-notarize": "0.2.0"
Target: mac (DMG)
Platform: mac **not** MAS for macOS Catalina
The electron-builder config is:
target: 'dmg',
type: 'distribution',
hardenedRuntime: false,
entitlements: './config/packaging/macosEntitlements.plist',
entitlementsInherit: './config/packaging/macosEntitlements.plist',
gatekeeperAssess: false,
And the entitlements are (as a minimum):
<!-- The bare minimum is these 3, according to Electron docs -->
<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/>
<!-- Camera and microphone are needed, not sure why?! -->
<key>com.apple.security.device.camera</key>
<true/>
<key>com.apple.security.device.microphone</key>
<true/>
The application now opens. But can't access the disc at all. We're having to tell the user to fix this themselves by turning on options in Security & Privacy for our application. Ugly. We're going to try asking them to open the root folder to get the perms, but that is also pretty ugly.
VS Code is built with Electron, but doesn't suffer this problem! I don't know what their work around is.
We've discovered that if in doubt, reset the perms that your application is asking for by running this sort of thing on the Mac you're testing out installations on:
tccutil reset All com.YourCompanyName.YourAppName
This just resets all the requests your app has made to the OS. After doing this, our application behaved a lot more normally and the OS asked for perms to access different folders as we'd expect. Unfortunately, we're not sure why. But using this was a massive improvement.
@semireg man you saved me! Your investigation totally makes sense. I was struggling with notarization for a few days and it's completely wrong. Today I've passed the review.
I'm able to confirm you don't need notarization for MAS. Ensure that if you have native modules you have to unpack them from asar. If you sign your application the "developer cant be verified" problem on Catalina related only to dynamically unpacking modules.
@klen how to know which native modules need to be unpacked from asar?
how to know which native modules need to be unpacked from asar?
All of 'em, I would say. See:
https://github.com/electron-userland/electron-builder/issues/4040#issuecomment-545493098
@Blightysoft hi, did you find a way to sign with hardened runtime and runs fine eventually?
Since Apple is going to stop apps without hardened runtime from opening after February 2020, it's worrying me very much...
@Blightysoft hi, did you find a way to sign with hardened runtime and runs fine eventually?
Since Apple is going to stop apps without hardened runtime from opening after February 2020, it's worrying me very much...
Finally, the app went blank after hardened runtime code sign because my entitlements miss a key-value pair:
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
Spent couples of days trying every possible solution...hope this would help someone like me.
this is my entitlements. If I delete dylib in project and set "hardenedRuntime": false, it work. but add dylib, it crash on open.
Hi all!
Two questions:
My MAS app builds and runs fine if I don't add this to the entitlements.plist
com.apple.security.app-sandbox
Is this this required or not? Can I submit the app to App Store without it?
The MAS builds seems to generate an executable AND an installer (PKG). However, the latter uses default icons, text etc and I don't see any options in electron builder docs to set these.
I mean, the options available for "PKG" builds are not available for MAS. Can customize the generated pkg installer somehow?
@gtamas
To upload a macOS app to be notarized, you must enable the Hardened Runtime capability. For more information about notarization, see Notarizing macOS Software Before Distribution.
To distribute a macOS app through the Mac App Store, you must enable the App Sandbox capability.
Please read the documentation of apple carefully, then you'll understand it.
Resolved? I'm facing the same problem. I haved changed my entitlements files many times, added lots of entitlements, but useless.
Here is my entitlements.mas.parent.plist
<?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>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>XXX.com.aaa.bbb</string>
</array>
<key>com.apple.application-identifier</key>
<string>XXX.com.aaa.bbb</string>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<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.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
Error Message:
Logical CPU: 2
Error Code: 0x00000015 (invalid protections for user instruction write)
Trap Number: 14
Solved! We now have the MAC (not MAS) hardened runtime working on Apple macOS. I hope this review might help others:
The Apple notarising process was spewing out false positives, so there was officially no problem, until our application died when running on a Mac, and created a dump file. Then it was difficult for Apple support to work out what the problem was.
Sometime on or before 10th April 2020, Apple (finally) did some upgrading work on their notarising process, an Apple Tech Support chap told me. It meant that we finally got some meaningful error messages, although over a couple of days (9th / 10th) the messages altered. Each run seemed to wipe out the previous 'https://osxapps-ssl.itunes.apple.com/...' logs and made them show the latest results as though they are their own?!
The Apple logs eventually had the error "Embedded entitlements are invalid: syntax error near line 1". Their docs claim this means the entitlements file is in a binary format. In order to help the support engineer by providing the binary to which the entitlements had been applied, we had to create a new stand alone Azure (macOS) pipeline since you can't export artefacts from their releases pipelines. And this new pipeline worked like a charm! Notarising passed, and the software opened correctly on the Mac.
It seems as though passing the code over from the main Azure (Windows) pipeline to the releases (macOS) pipeline somehow damaged the entitlements.plist file? There is a nagging suspicion that in 6 months time, Apple will suddenly say that there is no problem.
One curious anomaly, is that although we're using the exact same Azure pipeline agent specification as before, 10.15, Taccy previously though that the software had been build on macOS 10.13 and now thinks it is 10.15. Or perhaps that is a reflection on the version used by Apple itself to notarise?
So the problem is solved. One of the things we've found incredibly frustrating is that Apple do not provide engineer tools to work out what is going on, hence the use of Taccy et al. Frankly, their ecosystem support is nowhere near as good as Microsoft.
<dict>
<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.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.device.camera</key>
<true/>
<key>com.apple.security.device.microphone</key>
<true/>
</dict>
Making sure the path to the entitlements file was relative './...'
Removing comments from the plist file might have helped (?)
Endlessly changing the entitlements
Downgrading the Electron version to 6.x or 7.x
Hope this is of some use!
Has any one been able to narrow down what caused this crash? Same misery here. Mac Build, Electron-Builder 22.7.0, hardenedRuntime=true, Crash with code signature invalid on app launch.
Got it to build and notarized. Have to use the default entitlement for both main and inherit.
Electron-builder: 22.7.0
Traget: mac
hardenedRuntime = true.
<?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>
<!-- https://github.com/electron/electron-notarize#prerequisites -->
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<!-- https://github.com/electron-userland/electron-builder/issues/3940 -->
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
Any other setting causes code signature invalid error.
Looks like building for mas is a whole new can of worms.
Had the same issue but @monoto 's fix for the lists worked for me.
I'm building for pkg.
Thanks @monoto
Thanks guys! I was starting to go bald already.
This is what was happening for me in a project completely unrelated to Electron: I had some binaries (go-flutter-desktop actually) and they loaded a dylib
bundled along with them in a .dmg
which caused the .app
to crash on start when signed for hardened runtime.
It transpired this action requires Allow Unsigned Executable Memory Entitlement during the codesign operation with options=runtime
enabled. Without this entitlement the app just crashed on start with no intelligible error message.
Thanks to you lot I figured which entitlement was missing by trial and error.
Incase this helps anyone else, I was having issues with this where I was able to successfully notarize and sign my app but it would crash and close upon opening.
I was letting Electron-Builder sign my app for me, but using a custom script after the fact to sign additional files that Apple's notarization would complain about. (As well build and sign a PKG file containing my Electron app.)
_I realized my script was replacing the existing code signing done by Electron, and was not re-applying the entitlements that I had setup via the package.json file in my Electron workflow._
Ultimately I got things working by not using the Electron signing process at all (You can totally get this working via Electron-Builder, I just didn't want to move my automation scripts from my current workflow.). Here are all my settings:
Pacakge.json configurations: (build => mac)
"mac": {
"icon": "./build/icon.icns",
"gatekeeperAssess": false,
"hardenedRuntime": true,
"entitlements": "build/entitlements.mac.inherit.plist",
"entitlementsInherit": "build/entitlements.mac.inherit.plist",
"target": ["zip"]
},
Entitlements File: (inside my 'build' folder, located at root of my project)
<!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.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.disable-executable-page-protection</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
</plist>
Command for Building App via Electron: (Again, I was not using Electron Builder for signing, to use electron builder remove the '-c.mac.identity=null' part. '-m' specifies to build specifically for Mac platform)
electron-builder -m -c.mac.identity=null
My Signing Script Process:
In addition to signing the main .app file, I sign all of the following files individually first (deep sign does not seem to do this for me):
For each of these files I sign, I use this command:
codesign --force --deep --options runtime --sign "My Signing ID" "Path/to/My/App"
For the main executable I use:
codesign --entitlements "Path/to/My/EntitlementsFile" --force --deep --options runtime --sign "My Signing ID" "Path/to/My/App"
I think the entitlements get inherited from the main app, which is why it seems to work for me not applying the entitlements to all the framework and executable files.
Then, to verify:
codesign -vvv --deep --strict "Path/to/My/App"
Some Notes About my App's Functionality:
Some Links That Were Helpful:
Runtime Entitlements and Explanations: https://developer.apple.com/documentation/security/hardened_runtime
Electron Options for Mac: https://www.electron.build/configuration/mac
Signing with Entitlements via Command Line: https://stackoverflow.com/questions/36888535/how-do-i-resign-app-with-entitlements
I was experiencing this problem for over two days and I couldn't find the solution for it online, and I tried everything that I read.
Finally, out of desperation, I downloaded the source code for electron-osx-sign and tried to find answers there. What I found was that I could enable debugging by adding this export:
export DEBUG=electron-osx-sign*
Scrutinizing the debug output, I saw this warning:
electron-osx-sign:warn No `entitlements` passed in arguments:
* Provide `entitlements` to specify entitlements file for codesign.
So, I added the following argument to electron-osx-sign to provide my entitlements:
--entitlements=./build/entitlements.mac.plist
Running electron-osx-sign again, I saw two new warnings:
electron-osx-sign:warn No `entitlements-inherit` passed in arguments:
* Entitlements file for enclosed app files is default to: /Users/Brian/Code/my-app/node_modules/electron-osx-sign/default.entitlements.darwin.inherit.plist +1ms
electron-osx-sign:warn No `entitlements-loginhelper` passed in arguments:
* Entitlements file for login helper is default to: ./build/entitlements.mac.plist +4ms
So, I added the following arguments to electron-osx-sign to provide my entitlements-inherit and entitlements-loginhelper:
--entitlements-inherit=./build/entitlements.mac.plist
--entitlements-loginhelper=./build/entitlements.mac.plist
````
It appears that I could have skipped adding `-entitlements-loginhelper=./build/entitlements.mac.plist` because it was defaulted to my `./build/entitlements.mac.plist` entitlements, but I wanted to remove the warning for a clean run.
After doing this, all the warnings went away and I was able to run my signed app, notarize it, and make a DMG installer for it using electron-installer-dmg. Everything is working perfectly now.
My entitlements.mac.plist file looks like:
```xml
<?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.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/>
</dict>
</plist>
I'm left with a few questions:
Why weren't entitlements and entitlements-inherit picked up from my package.json file? It appears that electron-osx-sign doesn't look for these settings:
"mac": {
"icon": "./assets/icons/mac/my-app.icns",
"hardenedRuntime": true,
"entitlements": "./build/entitlements.mac.plist",
"entitlementsInherit": "./build/entitlements.mac.plist",
"target": [
"dmg",
"zip"
]
}
What should be in my entitlements file and what should be in my entitlements-inherit file? Should they both be the same? If so, why do we have two different settings? I am unable to find clear and concise documentation on this. When I reviewed Visual Studio Code's signing, they appear to use the same file for both entitlements and entitlements-inherit.
For a darwin build vs. mas, do I even need this? Should it be empty? I didn't like seeing the warning in the electron-osx-sign debug output, so I added the --entitlements-loginhelper pointing to my entitlements file, which is what electron-osx-sign does anyway, to remove the warning.
Best,
Brian
The Apple logs eventually had the error "Embedded entitlements are invalid: syntax error near line 1". Their docs claim this means the entitlements file is in a binary format. In order to help the support engineer by providing the binary to which the entitlements had been applied, we had to create a new stand alone Azure (macOS) pipeline since you can't export artefacts from their releases pipelines. And this new pipeline worked like a charm! Notarising passed, and the software opened correctly on the Mac.
It seems as though passing the code over from the main Azure (Windows) pipeline to the releases (macOS) pipeline somehow damaged the entitlements.plist file? There is a nagging suspicion that in 6 months time, Apple will suddenly say that there is no problem.
Blightysoft on Apr 18
For anyone coming across this mentioned issue (Embedded entitlements are invalid: syntax error near line 1
) and did also build on Windows, but then tried to sign+notarize on macOS:
I just got the same issue after I made my GitLab pipeline take the entitlements file as an artifact from a Windows runner, to then download it to the macOS runner. Somehow that breaks the file, but it's not the encoding (I confirmed that it stayed the same). Downloading the entitlements file as a fresh copy from my git repo works without issues, but that doesn't work for my pipeline details.
The quoted comment helped me to figure this one out, though! To fix it you want to use plutil
to convert the entitlements file (after downloading it as an artifact from a Windows runner in my case):
Ensure Properly Formatted Entitlements
Command line tools and apps use entitlements to gain access to system resources and capabilities. The file that declares an app’s entitlements must be ASCII-encoded and must not include Unicode Byte Order Marks (BOMs). When using Xcode to code sign, Xcode ensures that the entitlements file is a well-formed XML property list with no extra characters. It also automatically converts entitlement files stored as binary property lists (bplist) into properly-formed XML properly lists.
When using a custom workflow, use the plutil utility to ensure proper formatting of your entitlements file. This is especially true if you manually edit the file. Validate the formatting before passing your entitlements file as an argument to the codesign utility. The convert option converts the entitlements to an XML property list, and the lint option verifies proper formatting:
% plutil -convert xml1 <Project_Name.entitlements> % plutil -lint <Project_Name.entitlements>
Running the command to convert
did the trick.
This was an exceptionally helpful post ! Thank you all for the in-depth comments.
In the end, keeping my entitlements as per instructed here: https://medium.com/@TwitterArchiveEraser/notarize-electron-apps-7a5f988406db .. and adding one extra com.apple.security.cs.allow-dyld-environment-variables
did the trick!
<plist version="1.0">
<dict>
<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.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
In my case, removing
<key>com.apple.security.app-sandbox</key>
<true/>
from my mac plist did the trick. FWIW my target platform was not mas but only mac.
Most helpful comment
Awesome! Im happy to report we've solved _all_ the build problems that we've been experiencing. Thank you @johannesjo, this was the issue driving us up a wall :joy:
entitlements for mac:
mac entitlementsInherit is the same as regular mac entitlements
MAS entitlements:
MAS entitlementsInherit: