metanorma / packed-mn

Single binary for Metanorma
https://www.metanorma.org
4 stars 1 forks source link

Create signed/notarized macOS binary (was: "Compiled asset at GH release loses execute permissions") #17

Open w00lf opened 4 years ago

w00lf commented 4 years ago

Currently, our github action build creates a new release with compiled binary asset attachment, however, such upload is lacking execute permissions so it need to be packed to execute container - dmg

ronaldtse commented 4 years ago

@w00lf apparently there is the way to do so: https://forums.developer.apple.com/thread/120989

But it's kind of complicated, and I wonder if it's easier to just distribute the packed-mn via Homebrew https://github.com/metanorma/homebrew-metanorma. (and we can make it an option to install the single binary vs the development chain).

Thoughts @opoudjis @CAMOBAP795 ?

ronaldtse commented 4 years ago

We might be able to use https://www.electron.build to sign the executable within a DMG, done just like in: https://github.com/ituob/itu-ob-editor/blob/master/.github/workflows/build-electron.yml

So it should be possible.

ronaldtse commented 4 years ago

Seems like we need to first package the binary in a DMG or PKG format from the Apple Community post above.

Here's some command line guidance for creating a DMG file: https://askubuntu.com/questions/1117461/how-do-i-create-a-dmg-file-on-linux-ubuntu-for-macos

And we can also use this to create a PKG installer: https://medium.com/swlh/the-easiest-way-to-build-macos-installer-for-your-application-34a11dd08744

Then we can sign + notarize the DMG / PKG using the electron builder command electron-builder.

ronaldtse commented 4 years ago

For the record, this is what we need to do on the "executable" itself:

From https://forums.developer.apple.com/thread/120989

  • Use the 10.9 or later SDK. Notarisation requires this because it confirms that your program is using modern code signing.
  • Make sure you specify a deployment target using -mmacosx-version-min. This causes clang to add the relevant Mach-O load command (LC_VERSION_MIN_MACOSX or LC_BUILD_VERSION, depending on how far back you support) that’s required by the notarisation system to confirm that you’re built with the 10.9 or later SDK.
  • Pass --timestamp to codesign to get a secure timestamp.
  • Pass -o runtime to codesign to enable the hardened runtime.
  • If you need to opt out of specific hardened runtime features, put the relevant entitlements in a .entitlements property list and pass that to codesign via the --entitlements option. See Hardened Runtime Entitlements for more on these entitlements.
  • Sign your tool with your Developer ID Application identity.
  • Notarise the outermost container (for example, if you have a tool in a .pkg on a .dmg, notarise the .dmg).

(The last step would be for Electron Builder)

ronaldtse commented 4 years ago

But it's kind of complicated, and I wonder if it's easier to just distribute the packed-mn via Homebrew https://github.com/metanorma/homebrew-metanorma. (and we can make it an option to install the single binary vs the development chain).

This is done in https://github.com/metanorma/homebrew-metanorma/issues/53.

The original issue on DMG building still applies.

CAMOBAP commented 3 years ago

@ronaldtse to be on the same page we still plan to pack DMG or PKG for packed-mn. If so do we have a plan to distribute it via AppStore or somehow else?

ronaldtse commented 3 years ago

Yes we should go the way of PKG or DMG. We will need to sign the DMG/PKG, which is doable. The problem is that this is a command line tool, which is a bit strange for a package, but I guess it’s something that we need to do.

CAMOBAP commented 3 years ago

PKG can be simply created by mkdir -p ./usr/local/bin && cp build ./usr/local/bin && productbuild --root ./usr/local/bin --timestamp --sign "${SING_IDENTITY}" Product-mn-2.pkg

To get this sign identity we need to register in Apple developer program https://developer.apple.com/enroll

To generate DMG we also need to be members of Apple developer program

FYI @ronaldtse

ronaldtse commented 2 years ago

@CAMOBAP sorry I missed this. We are a member of the program. A signed binary requires Apple notarisation. This thread gives a good example of what needs to be done:

https://developer.apple.com/forums/thread/130379

Contents re-formatted below.


1) Sign your dylibs 2) Sign your executables 3) Build an installer package 4) Sign and notarize the installer package

You can incorporate all of that into your build process if you want. It is very easy. Back when Catalina disabled 32-bit apps, a few people freaked out over ghostscript. Apparently nobody had bothered to rebuild that since 32-bit days. I built and notarized a 64-bit version in a few minutes. The hardest part was fixing the bugs in ghostscript iteslf so it would build on a modern machine.

Sign executables:

codesign --timestamp --options=runtime -s "Developer ID Application: ***" -v bin/gs
codesign --timestamp --options=runtime -s "Developer ID Application: ***" -v bin/pdftoraster
codesign --timestamp --options=runtime -s "Developer ID Application: ***" -v cups/pstoraster
codesign --timestamp --options=runtime -s "Developer ID Application: ***" -v cups/pstopxl

I assume you will have to sign dylibs too. If your software is doing anything funky, you may need additional hardened runtime entitlements.

I was building this from source. So I signed the working copy and then installed.

sudo make install

Now, I needed to create a temp install for the installer package. Your files will, of couse, be different. This is also on a VM where there is nothing in /usr/local except for ghostscript.

sudo mkdir /tmp/ghostscript
ditto /usr/local/bin /tmp/ghostscript/usr/local/bin
ditto /usr/local/share /tmp/ghostscript/usr/local/share
ditto /usr/libexec/cups/filter/pdftoraster /tmp/ghostscript/usr/libexec/cups/filter/
ditto /usr/libexec/cups/filter/pstoraster /tmp/ghostscript/usr/libexec/cups/filter/
ditto /usr/libexec/cups/filter/pstopxl /tmp/ghostscript/usr/libexec/cups/filter/
ditto /private/etc/cups/pdftoraster.convs /tmp/ghostscript/private/etc/cups/
ditto /private/etc/cups/pstoraster.convs /tmp/ghostscript/private/etc/cups/

Now create the installer.

productbuild --identifier "com.***.ghostscript64.pkg" --sign "Developer ID Installer: ***" --timestamp --root /tmp/ghostscript / ghostscript64.pkg

Notarize the installer.

xcrun altool --notarize-app --primary-bundle-id "com.***.ghostscript64.pkg" --username “developer@***" --password "..." --file ghostscript64.pkg

Wait for the e-mail or ping the server if you are impatient. An automated system would need to do something clever here. The altool can emit XML output that is easier to parse if you need to.

xcrun altool --notarization-history 0 -u "developer@***" -p "..."

Once you are notarized, staple the ticket.

xcrun stapler staple ghostscript64.pkg