2

I know this is long so here's a real brief summary:

  • I am trying to build an application and copy other pre-built scripts or files into the .app/Contents/MacOS directory.

  • I can get something that works and still prompts the user for mic access but it won't pass notarization (saying the signature is bad). I can't tell if I'm building the DMG and/or PKG in an improper way or maybe copying files into the install destination hoses the signature?

  • If I copy the pre-built files in place and then re-sign my app after archiving I can pass Apple's notarization but then the mic access fails crashing with a privacy violation (as if I never specified entitlements).

Here's the longer version with much detail:

I have an application myApp that uses the microphone that I build as an archive from the command line with xcodebuild -scheme myApp archive -archivePath myApp.archive.

The app works if I were to stop here. I have the proper entitlements, code hardening enabled and the NSMicrophoneUsageDescription in my plist.

However, I have various other resources that I must include with my app. I want to put them in the myApp.app/Contents/MacOS dir. These resources include a shell script for debugging, a secondary Swift tool, etc.

I am finding it impossible to build this app with the proper signature and entitlements for mic access in conjunction with passing Apple's notarization.

I am copying these secondary apps into the destination dir by specifying a pre-action and post-action script in Xcode for the Archive action in my scheme.

Pre-Action Archive Script

The pre-action script is signing all the secondary objects with my Developer ID Application certificate:

    APP_SIGN_ID="Developer ID Application: MyCompany Inc. (XXXXXXXXXX)"
    LOG="/tmp/archive.log"
    rm -f $LOG
    echo "Pre-action for archive" > $LOG

    function sign_and_verify() {
       echo "signing $1" >> $LOG
       codesign --force --options runtime --verify --verbose --sign "$APP_SIGN_ID" "$1"
       if [ $? -ne 0 ]; then
         echo "failed signature" >> $LOG
         exit 1
       fi
    }

    # sign these things as a pre-action to archive and copy them to the Contents/MacOS in the post-action
    sign_and_verify "${HOME}/src/bin/mydebugtool"
    sign_and_verify "${HOME}/src/bin/myscript.sh"

Post-Action Archive Script

The post-action script for the archive in my scheme is copying these signed assets into place (the copy has to be done as a post-action b/c the archive destination dir doesn't exist in the pre-action phase):

    LOG="/tmp/archive.log"
    TARGETDIR="${ARCHIVE_PRODUCTS_PATH}/Applications/myApp.app/Contents/MacOS/"

    function my_copy() {
        echo "copying $1 to $2" >> $LOG
        cp "$1" "$2"
        if [ $? -eq 0 ]; then
            echo "copy success" >> $LOG
        else
            echo "copy failure" >> $LOG
        fi
    }

    my_copy "${HOME}/src/bin/mydebugtool" "${TARGETDIR}"
    my_copy "${HOME}/src/bin/myscript.sh" "${TARGETDIR}"

I then build this archive. If I run open <path-to-archive>/myApp.app it opens properly and prompts for mic access. The other tools are correctly in the archive.

Notarization Output

However, when I bundle the archive contents into a DMG or PKG it fails notarization with:

    {
      "logFormatVersion": 1,
      "jobId": "5a225fdb-d85d-41fa-8bde-1026xx92331a",
      "status": "Invalid",
      "statusSummary": "Archive contains critical validation errors",
      "statusCode": 4000,
      "archiveFilename": "myApp.dmg",
      "uploadDate": "2019-08-20T20:22:08Z",
      "sha256": "d93da550d2617246aead790a13afc6360ff5198764cfb779b785e06d463d4e32",
      "ticketContents": null,
      "issues": [
        {
          "severity": "error",
          "code": null,
          "path": "myApp.dmg/myApp.app/Contents/MacOS/myApp",
          "message": "The signature of the binary is invalid.",
          "docUrl": null,
          "architecture": "x86_64"
        }
      ]
    }

It's a shame it fails because it runs great on Mojave. It'll just never run on Catalina without passing notarization.

So I can't tell if it's failing because of the way I'm building the DMG or PKG or if it's failing because I'm putting things into the Contents/MacOS directory (even though they are signed?).

How I build a DMG

For the sake of clarity, here's the little script I use to assemble the DMG I'm trying to get notarized:

    BASE_DIR=`pwd`"/myapp.archive.xcarchive/Products/Applications"


    function create_dmg() {
      echo "creating DMG"
      rm -f temp.dmg
      rm -f myApp.dmg
      title=myApp
      size=240
      umount /Volumes/myApp
      hdiutil create -srcfolder "${BASE_DIR}" -volname "${title}" -fs HFS+ \
          -fsargs "-c c=64,a=16,e=16" -format UDRW -size ${size}m temp.dmg
      device=$(hdiutil attach -readwrite -noverify -noautoopen temp.dmg | \
             egrep '^/dev/' | sed 1q | awk '{print $1}')
      mkdir /Volumes/"${title}"/.background
      cp background.png /Volumes/"${title}"/.background/background.png
      ln -s /Applications /Volumes/"${title}"/"Applications"
      rm -rf /Volumes/"${title}"/.fseventsd

      sleep 2
      echo '
       tell application "Finder"
         tell disk "'${title}'"
               open
               set current view of container window to icon view
               set toolbar visible of container window to false
               set statusbar visible of container window to false
               set the bounds of container window to {400, 100, 950, 500}
               set theViewOptions to the icon view options of container window
               set arrangement of theViewOptions to not arranged
               set icon size of theViewOptions to 150
               set background picture of theViewOptions to file ".background:'background.png'"

               set position of item "myApp" of container window to {120, 150}
               set position of item "Applications" of container window to {430, 150}

               set position of item ".background" of container window to {120, 525}
               set position of item ".Trashes" of container window to {220, 525}
               set position of item ".DS_Store" of container window to {320, 525}
               set position of item ".fseventsd" of container window to {430, 525}

               update without registering applications
               delay 5
         end tell
       end tell
      ' | osascript

      sync
      sync

How I build a PKG

I also am building a PKG which also fails notarization. Here's my script for building the PKG:

    PKG_SIGN_ID="Developer ID Installer: My Company Inc. (XXXXXXXXX)"
    BASE_DIR=`pwd`"/myapp.archive.xcarchive/Products/Applications"

    function create_pkg() {
      echo "creating pkg"
      rm -f myApp.pkg

      # generate plists
      cd $BASE_DIR
      pkgbuild --analyze --root ./myApp.app myApp.plist

      # pkgbuild myApp
      pkgbuild --scripts /tmp/installer-scripts --root "./myApp.app" --component-plist "./myApp.plist" --identifier "com.mycompany.myapp.myApp" --version "$VERSION" --install-location "/Applications/myApp.app" ./myApp.pkg
      if [ $? -ne 0 ]; then
        echo "failed pkgbuild for myApp.pkg"
        rm -f myApp.pkg
        exit 1
      fi


      # copy the installer resources
      cp -r ../../res ./

      # --synthesize will generate the Distribution.xml file
      productbuild --synthesize --resources ./res --package myApp.pkg Distribution.xml
      if [ $? -ne 0 ]; then
        echo "failed productbuild synthesize for Distribution.xml"
        rm -f myApp.pkg
        exit 1
      fi

      # add our title to the Distribution.xml that was generated
      # I can't believe I have to splice this in after the synthesize but I couldn't find another way
      cat Distribution.xml | sed $'3i\\\n<title>MyApp</title>\n' > mod.xml
      mv mod.xml Distribution.xml
      cat Distribution.xml | sed $'3i\\\n<welcome file="welcome.html"/>\n' > mod.xml
      mv mod.xml Distribution.xml
      cat Distribution.xml | sed $'3i\\\n<background file="background.png" mime-type="image/png" scaling="tofit"/>\n' > mod.xml
      mv mod.xml Distribution.xml
      cat Distribution.xml | sed $'3i\\\n<background-darkAqua file="background.png" mime-type="image/png" scaling="tofit"/>\n' > mod.xml
      mv mod.xml Distribution.xml

      productbuild --resources ./res --sign "$PKG_SIGN_ID" --distribution Distribution.xml myApp.$VERSION.pkg

      if [ $? -ne 0 ]; then
        echo "failed signature"
        rm -f myApp.pkg
        exit 1
      else
        echo "Successfully built and signed myApp.$VERSION.pkg"
        mv myApp.$VERSION.pkg ../../../
        # remove the unsigned package so we don't accidentally distribute that
        rm -f myApp.pkg
      fi
    }

I hope this isn't so long that someone who can help has stopped reading. I tried to be brief yet also include as much detail as I think appropriate.


UPDATE: to verify whether I'm improperly building a DMG I commented out the post-action archive script, built the app and the DMG and got it notarized. So something about me putting files into the Contents/MacOS dir as part of the archive post-action is breaking the signature.

**

spartygw
  • 3,289
  • 2
  • 27
  • 51
  • 1
    "If I copy the pre-built files in place and then re-sign my app after archiving I can pass Apple's notarization but then the mic access fails crashing with a privacy violation (as if I never specified entitlements)" - this seems like a good approach. What's your command line for resigning? Are you specifying the entitlements? – TheNextman Aug 21 '19 at 03:02
  • @TheNextman - holy crap, dude. I was not passing entitlements on the codesign command line when resigning. Please send me venmo or paypal info I would like to thank you. – spartygw Aug 21 '19 at 15:17
  • 1
    Also, add --timestamp flag. – Parag Bafna Aug 21 '19 at 18:09

0 Answers0