In this thread:https://forums.developer.apple.com/thread/121813For a signed, notarized, and stapled DMG with a signed MacOS app distributed over the internet.If the computer is offline and a notarized DMG has a notary ticket stapled to it, it is possible to copy an App to Applications and validate the app as long as the DMG is still mounted.However, if the DMG is unmounted before the App is run, the App will fail validation.From the very helpful @eskimo> If you staple the ticket to the .dmg, the system will ingest that ticket when the quarantined
.dmg is mounted.
I verified that worked on an offline computer on MacOS 10.15. However I found another scenario:Pre-req: Notarized DMG with ticket stapled to it1. Somehow copy the DMG to the computer/VM2. Turn off network access3. Open the DMG4. Drag the App to Applications5. Unmount the DMG6. Open the App7. Fails verification because the App does not have the ticket stapled to it.Workaround: We can tell customers to keep the DMG mounted the first time they open the app and/or to make sure they have internet access. (or paths through their firewall to Apple services for Gatekeeper?)How should one go about stapling the notary ticket to the App inside the notarized DMG?Do we really need to:1. Sign the app2. Zip it3. Notarize the zip4. Unzip it and staple the ticket to the App5. Put the app with the notary ticket stapled to it into a DMG and sign the DMG6. Notarize the DMG7. Staple the ticket to the DMGSo two notary processes to make sure the above process succeeds?Or is there any way to staple the ticket to the notarized DMG's app? Wouldn't that change the DMG and cause validation to fail?Type of Customer:Downloads DMG on a separate computer with internet access and distributes on their intranet to user computers that don't have internet access.Thanks.
Post
Replies
Boosts
Views
Activity
First off I submitted a bug report at https://developer.apple.com/bug-reporting/Using Xcode 11.3 and command line utilities.Bug: "codesign" command line utility always prints to stderr.This confused me while I was trying to test that codesigning succeeded as part of a continuous integration script.NOTE that you may use the codesign return value to test success or failure.Workaround: One liner to save only stderr output from a command to a variable and print stdout:{ stderr_only="$( { codesign ${=CSVARS} $SIG "$APP_NAME"; } 2>&1 1>&3 3>&- )"; } 3>&1;
ret_val=$?
echo "Return val: $ret_val"
echo "Codesign stderr only: $stderr_only"Script to reproduce#!/bin/zsh
#codesign_prints_to_stderr.sh
export CSARGS="-f --verbose --timestamp -o runtime --sign "
#NOTE: Replace with a valid signature
export SIG="Developer ID Application: Your Company (ID)"
#NOTE: Replace with a valid app folder
export APP_NAME="TestApp.app"
echo "codesign ${=CSARGS} $SIG \"$APP_NAME\""
unset save_stdout save_stderr save_return_val
eval "$( ( codesign ${=CSARGS} $SIG "$APP_NAME" ) \
2> >(save_stderr=$(cat); typeset -p save_stderr) \
> >(save_stdout=$(cat); typeset -p save_stdout); save_return_val=$?; typeset -p save_return_val )"
echo "Return Value: $save_return_val"
echo "Saved stdout: $save_stdout"
echo "Saved stderr: $save_stderr"
echo "codesign -dvvv \"$APP_NAME\""
unset save_stdout save_stderr save_return_val
eval "$( ( codesign -dvvv "$APP_NAME" ) \
2> >(save_stderr=$(cat); typeset -p save_stderr) \
> >(save_stdout=$(cat); typeset -p save_stdout); save_return_val=$?; typeset -p save_return_val )"
echo "Return Value: $save_return_val"
echo "Saved stdout: $save_stdout"
echo "Saved stderr: $save_stderr"Example output.1. Success: Nominal case prints to stderr:./codesign_prints_to_stderr.sh
codesign -f --verbose --timestamp -o runtime --sign Developer ID Application: Your Company (ID) "TestApp.app"
Return Value: 0
Saved stdout:
Saved stderr: TestApp.app: signed app bundle with Mach-O thin (x86_64) []2. Error case: FakeApp doesn't exist./codesign_prints_to_stderr.sh
codesign -f --verbose --timestamp -o runtime --sign Developer ID Application: Your Company (ID) "FakeApp.app"
Return Value: 1
Saved stdout:
Saved stderr: FakeApp.app: No such file or directory3. Error case: Developer ID doesn't exist./codesign_prints_to_stderr.sh
codesign -f --verbose --timestamp -o runtime --sign Developer ID Application: FakeID (FAKE) "TestApp.app"
Return Value: 1
Saved stdout:
Saved stderr: Developer ID Application: FakeID (FAKE): no identity found4. Error case: App already signed:./codesign_prints_to_stderr.sh
codesign --verbose --timestamp -o runtime --sign Developer ID Application: Your Company (ID) "TestApp.app"
Return Value: 1
Saved stdout:
Saved stderr: TestApp.app: is already signed5. Success: force re-sign the app:./codesign_prints_to_stderr.sh
codesign -f --verbose --timestamp -o runtime --sign Developer ID Application: Your Company (ID) "TestApp.app"
Return Value: 0
Saved stdout:
Saved stderr: TestApp.app: replacing existing signature
TestApp.app: signed app bundle with Mach-O thin (x86_64) []6. Example "-d" output also goes to stderr:codesign -dvvv "TestApp.app"
Return Value: 0
Saved stdout:
Saved stderr: Executable=/Users/YourName/Projects/testApp/TestApp.app/Contents/MacOS/TestApp
Identifier=
Format=app bundle with Mach-O thin (x86_64)
CodeDirectory v=20500 size=332 flags=0x10000(runtime) hashes=4+3 location=embedded
Hash type=sha256 size=32
... (rest is all in stderr)