Skip to content

Instantly share code, notes, and snippets.

@mdeggies
Last active November 8, 2019 18:09
Show Gist options
  • Save mdeggies/7dd51abe22d919820b04eff8883f2cb8 to your computer and use it in GitHub Desktop.
Save mdeggies/7dd51abe22d919820b04eff8883f2cb8 to your computer and use it in GitHub Desktop.

Quick bash script that shows how to use the gon CLI tool on a remote OSX box to sign, package, staple, and notarize a product from releases.hashicorp.com. It also validates that the binary has been signed and notarized properly and can run on OSX 10.15.

Pre-reqs:

  • Your OSX box should have OSX 10.15+, wget, Xcode 11.1+, and SSH access enabled
  • Create a developer ID cert and add it to your login keychain on your OSX box
  • Set the following environment variables locally: SSH_USER, SSH_PWD, and REMOTE_IP
  • Edit config.json locally and replace the variables with real values
  • Ensure config.json, script.sh, and remote_script.sh are all in the same local dir

To run:

  • Run ./script.sh
{
"source" : ["/Users/$user/input/$product/$product"],
"bundle_id" : "com.example.$product",
"apple_id": {
"username" : "[email protected]",
"password": "app-specific-password (see https://support.apple.com/en-us/HT204397)"
},
"sign" :{
"application_identity" : "$developer_id_cert (see https://github.com/mitchellh/gon#prerequisite-acquiring-a-developer-id-certificate for details)"
},
"zip" :{
"output_path" : "/Users/$user/output/$product/$product.zip"
}
}
#!/bin/bash
set -ex
user="$SSH_USER"
pass="$SSH_PWD"
remoteIP="$REMOTE_IP"
product="$PRODUCT"
inputDir="$PWD/input"
outputDir="$PWD/output"
version="0.12.13"
function setup {
mkdir -p "$inputDir/$product"
mkdir -p "$outputDir/$product"
# Unlock the login keychain where the apple developer ID cert is stored via SSH
# Details here: https://stackoverflow.com/a/52221673
security unlock-keychain -p "$pass" login.keychain
}
function download_release {
# Download the latest release, unzip, and store binary in the input dir
# If you're building locally, scp the file over instead and remove this step
curl -o "$product.zip" "https://releases.hashicorp.com/$product/$version/${product}_${version}_darwin_amd64.zip" ;
mv "$product.zip" "$inputDir/$product";
unzip -o "$inputDir/$product/$product.zip" -d "$inputDir/$product" && rm "$inputDir/$product/$product.zip";
}
function set_quarantine {
# Set quarantine on the binary to trigger gatekeeper failure
application="cURL"
date=$(printf %x $(date +%s))
uuid=$(/usr/bin/uuidgen)
/usr/bin/xattr -w com.apple.quarantine "0002;${date};${application};${uuid}" "$inputDir/$product/$product"
# Verify quarantine has been set with attr $file
gkVerification="$(xattr $inputDir/$product/$product)"
exit_status=$?
if [[ "$gkVerification" == *"com.apple.quarantine"* ]]; then
echo "Quarantine added"
else
echo "Quarantine could not be added"
exit $exit_status
fi
}
function install_gon {
/usr/local/bin/wget 'https://github.com/mitchellh/gon/releases/download/v0.2.1/gon_0.2.1_macos.zip' -O gon.zip
unzip -o gon.zip -d "$PWD" && rm "$PWD/gon.zip"
}
function run_gon {
# Run the signing, packaging, notarization, and stapling steps using gon
./gon -log-level=trace -log-json config.json
exit_status=$?
if [ $exit_status != 0 ]; then
echo "Error notarizing"
exit $exit_status
fi
}
function validate {
# Unzip and validate the notarized binary
unzip -o "$outputDir/$product/$product.zip" -d "$outputDir/$product"
# Run spctl verification
# Details here: https://eclecticlight.co/2019/05/31/can-you-tell-whether-code-has-been-notarized/
spctlVerification="$(spctl -a -vvv -t install $outputDir/$product/$product 2>&1)"
exit_status=$?
if [[ "$spctlVerification" == *"accepted"* ]] && \
[[ "$spctlVerification" == *"source=Notarized Developer ID"* ]] && \
[[ "$spctlVerification" == *"origin=Developer ID Application: Hashicorp, Inc."* ]]; then
echo "spctl verification successfull"
else
echo "spctl verification failed"
exit $exit_status
fi
# Run codesign verification
# Details here: https://eclecticlight.co/2019/05/31/can-you-tell-whether-code-has-been-notarized/
csVerification="$(codesign --test-requirement="=notarized" -vv $outputDir/$product/$product 2>&1)"
exit_status=$?
if [[ "$csVerification" == *"valid on disk"* ]] && \
[[ "$csVerification" == *"satisfies its Designated Requirement"* ]] && \
[[ "$csVerification" == *"explicit requirement satisfie"* ]]; then
echo "codesign verification successfull"
else
echo "codesign verification failed"
exit $exit_status
fi
}
function cleanup {
rm -rf "$inputDir/$product"
rm "$PWD/config.json"
}
setup
download_release
set_quarantine
install_gon
run_gon
validate
cleanup
#!/bin/bash
# Create local json gon config file (see https://github.com/mitchellh/gon#configuration-file for details)
# Set local environment variables SSH_USER, SSH_PWD, and REMOTE_IP
# Setup SSH with `ssh-keygen -R $remote-host` and `chmod 400 ~/.ssh/id_rsa`
# Invoke script with ./script.sh
set -ex
product="terraform"
outputDir="/Users/administrator/output"
# Copy gon config from local to remote
scp config.json "$SSH_USER@$REMOTE_IP:/Users/$SSH_USER/config.json"
# Run remote script on your provisioned OSX box
ssh -o StrictHostKeyChecking=no "$SSH_USER@$REMOTE_IP" SSH_USER="$SSH_USER" SSH_PWD="$SSH_PWD" REMOTE_IP="$REMOTE_IP" PRODUCT="$product" bash -s < "$PWD/remote_script.sh"
# Copy output zip file back to local
scp "$SSH_USER@$REMOTE_IP:$outputDir/$product/$product.zip" .
# Remove output dir
ssh -o StrictHostKeyChecking=no "$SSH_USER@$REMOTE_IP" "rm -rf $outputDir/$product"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment