ci: Notarize MacOS Binaries and Add Flat Package Installers (#3571)
* ci: Notarize MacOS * Modify logging and documentation to be better * Make a copy of certain parts of the deploy workflow * Delete testing workflow
This commit is contained in:
parent
4369c92d40
commit
955a0f7a33
|
@ -105,6 +105,100 @@ jobs:
|
||||||
name: ${{ matrix.name }}
|
name: ${{ matrix.name }}
|
||||||
path: ${{ matrix.name }}
|
path: ${{ matrix.name }}
|
||||||
|
|
||||||
|
# Notarize starship binaries for MacOS and build notarized pkg installers
|
||||||
|
notarize_and_pkgbuild:
|
||||||
|
runs-on: macos-latest
|
||||||
|
needs: github_build
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- target: x86_64-apple-darwin
|
||||||
|
arch: x86_64
|
||||||
|
name: starship-x86_64-apple-darwin.tar.gz
|
||||||
|
pkgname: starship-x86_64-apple-darwin.pkg
|
||||||
|
|
||||||
|
- target: aarch64-apple-darwin
|
||||||
|
arch: aarch64
|
||||||
|
name: starship-aarch64-apple-darwin.tar.gz
|
||||||
|
pkgname: starship-aarch64-apple-darwin.pkg
|
||||||
|
|
||||||
|
env:
|
||||||
|
KEYCHAIN_FILENAME: app-signing.keychain-db
|
||||||
|
KEYCHAIN_ENTRY: AC_PASSWORD
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Notarize | Set up secrets
|
||||||
|
env:
|
||||||
|
APP_CERTIFICATE_BASE64: ${{ secrets.APPLEDEV_APPSIGNKEY_BASE64 }}
|
||||||
|
INSTALL_CERTIFICATE_BASE64: ${{ secrets.APPLEDEV_INSTALLERSIGNKEY_BASE64 }}
|
||||||
|
P12_PASSWORD: ${{ secrets.APPLEDEV_SIGNKEY_PASS }}
|
||||||
|
KEYCHAIN_PASSWORD: ${{ secrets.APPLEDEV_SIGNKEY_PASS }}
|
||||||
|
APPLEID_USERNAME: ${{ secrets.APPLEDEV_ID_NAME }}
|
||||||
|
APPLEID_TEAMID: ${{ secrets.APPLEDEV_TEAM_ID }}
|
||||||
|
APPLEID_PASSWORD: ${{ secrets.APPLEDEV_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
APP_CERTIFICATE_PATH="$RUNNER_TEMP/app_certificate.p12"
|
||||||
|
INSTALL_CERTIFICATE_PATH="$RUNNER_TEMP/install_certificate.p12"
|
||||||
|
KEYCHAIN_PATH="$RUNNER_TEMP/$KEYCHAIN_FILENAME"
|
||||||
|
|
||||||
|
# import certificates from secrets
|
||||||
|
echo -n "$APP_CERTIFICATE_BASE64" | base64 --decode --output $APP_CERTIFICATE_PATH
|
||||||
|
echo -n "$INSTALL_CERTIFICATE_BASE64" | base64 --decode --output $INSTALL_CERTIFICATE_PATH
|
||||||
|
|
||||||
|
# create temporary keychain
|
||||||
|
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||||
|
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
|
||||||
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||||
|
|
||||||
|
# import certificates to keychain
|
||||||
|
security import $APP_CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||||
|
security import $INSTALL_CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||||
|
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||||
|
|
||||||
|
# Add Apple Developer ID credentials to keychain
|
||||||
|
xcrun notarytool store-credentials "$KEYCHAIN_ENTRY" --team-id "$APPLEID_TEAMID" --apple-id "$APPLEID_USERNAME" --password "$APPLEID_PASSWORD" --keychain "$KEYCHAIN_PATH"
|
||||||
|
|
||||||
|
- name: Notarize | Build docs
|
||||||
|
run: |
|
||||||
|
cd docs
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
- name: Notarize | Download artifacts
|
||||||
|
uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.name }}
|
||||||
|
path: artifacts
|
||||||
|
|
||||||
|
- name: Notarize | Unpack Binaries
|
||||||
|
run: tar xf artifacts/${{ matrix.name }}
|
||||||
|
|
||||||
|
- name: Notarize | Build, Sign, and Notarize Pkg
|
||||||
|
run: bash install/macos_packages/build_and_notarize.sh starship docs ${{ matrix.arch }} ${{ matrix.pkgname }}
|
||||||
|
|
||||||
|
- name: Notarize | Upload Notarized Flat Installer
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.pkgname }}
|
||||||
|
path: ${{ matrix.pkgname }}
|
||||||
|
|
||||||
|
- name: Notarize | Package Notarized Binary
|
||||||
|
run: tar czvf ${{ matrix.name }} starship
|
||||||
|
|
||||||
|
- name: Notarize | Upload Notarized Binary
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.name }}
|
||||||
|
path: ${{ matrix.name }}
|
||||||
|
|
||||||
|
- name: Cleanup Secrets
|
||||||
|
if: ${{ always() }}
|
||||||
|
run: |
|
||||||
|
KEYCHAIN_PATH="$RUNNER_TEMP/$KEYCHAIN_FILENAME"
|
||||||
|
security delete-keychain $KEYCHAIN_PATH
|
||||||
|
|
||||||
# Create GitHub release with Rust build targets and release notes
|
# Create GitHub release with Rust build targets and release notes
|
||||||
github_release:
|
github_release:
|
||||||
name: Create GitHub Release
|
name: Create GitHub Release
|
||||||
|
|
|
@ -28,3 +28,6 @@ Cargo.lock
|
||||||
# Compiled files for documentation
|
# Compiled files for documentation
|
||||||
docs/node_modules
|
docs/node_modules
|
||||||
docs/.vuepress/dist/
|
docs/.vuepress/dist/
|
||||||
|
|
||||||
|
# Ignore pkg files within the install directory
|
||||||
|
install/**/*.pkg
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?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>arch</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,115 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Envrionmental variables that need to be set. These are sane defaults
|
||||||
|
# KEYCHAIN_ENTRY=AC_PASSWORD # Or whatever you picked for <AUTH_ITEM_NAME>
|
||||||
|
# RUNNER_TEMP=~/Library/Keychains/
|
||||||
|
# KEYCHAIN_FILENAME=login.keychain-db
|
||||||
|
#
|
||||||
|
# Environmental variables that can be set if needed. Else they will default to
|
||||||
|
# values selected for the CI
|
||||||
|
#
|
||||||
|
# The identifier for the application signing key. Can be a name or a fingerprint
|
||||||
|
# APPLICATION_KEY_IDENT=E03290CABE09E9E42341C8FC82608E91241FAD4A
|
||||||
|
# The identifier for the installer signing key. Can be a name or a fingerprint
|
||||||
|
# INSTALLATION_KEY_IDENT=E525359D0B5AE97B7B6F5BB465FEC872C117D681
|
||||||
|
|
||||||
|
usage(){
|
||||||
|
echo "Builds, signs, and notarizes starship."
|
||||||
|
echo "Read readme.md in the script directory to see the assumptions the script makes."
|
||||||
|
echo "Usage: $0 <path-to-starship-binary> <path-to-docs-directory> <arch> [pkgname]"
|
||||||
|
echo " Example: $0 target/release/starship docs/ x64"
|
||||||
|
echo " Example: $0 target/debug/starship docs/ arm64 starship-1.2.1-arm64.pkg"
|
||||||
|
echo ""
|
||||||
|
echo "If no pkgname is provided, the package will be named starship-<version>-<arch>.pkg"
|
||||||
|
}
|
||||||
|
|
||||||
|
script_dir="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||||
|
source "$script_dir/common.sh"
|
||||||
|
|
||||||
|
if [[ -z ${KEYCHAIN_ENTRY+x} ]]; then
|
||||||
|
error "Environmental variable KEYCHAIN_ENTRY must be set."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z ${RUNNER_TEMP+x} ]]; then
|
||||||
|
error "Environmental variable RUNNER_TEMP must be set."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z ${KEYCHAIN_FILENAME+x} ]]; then
|
||||||
|
error "Environmental variable KEYCHAIN_FILENAME must be set."
|
||||||
|
fi
|
||||||
|
|
||||||
|
keychain_path="$RUNNER_TEMP/$KEYCHAIN_FILENAME"
|
||||||
|
if [[ ! -f "$keychain_path" ]]; then
|
||||||
|
error "Could not find keychain at $keychain_path"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z ${APPLICATION_KEY_IDENT+x} ]]; then
|
||||||
|
APPLICATION_KEY_IDENT=E03290CABE09E9E42341C8FC82608E91241FAD4A
|
||||||
|
echo "APPLICATION_KEY_IDENT not set. Using default value of $APPLICATION_KEY_IDENT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z ${INSTALLATION_KEY_IDENT+x} ]]; then
|
||||||
|
INSTALLATION_KEY_IDENT=E525359D0B5AE97B7B6F5BB465FEC872C117D681
|
||||||
|
echo "INSTALLATION_KEY_IDENT not set. Using default value of $INSTALLATION_KEY_IDENT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z ${3+x} ]]; then
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
starship_binary="$1"
|
||||||
|
starship_docs_dir="$2"
|
||||||
|
arch="$3"
|
||||||
|
pkgname="${4:-}"
|
||||||
|
|
||||||
|
if [[ ! -d "$starship_docs_dir/.vuepress/dist" ]]; then
|
||||||
|
error "Documentation does not appear to have been built!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ">>>> Signing binary"
|
||||||
|
codesign --timestamp --keychain "$keychain_path" --sign "$APPLICATION_KEY_IDENT" --verbose -f -o runtime "$starship_binary"
|
||||||
|
|
||||||
|
# Make ZIP file to notarize binary
|
||||||
|
if [ "$starship_binary" != "starship" ]; then
|
||||||
|
cp "$starship_binary" starship
|
||||||
|
fi
|
||||||
|
zip starship.zip starship
|
||||||
|
|
||||||
|
echo ">>>> Submitting binary for notarization"
|
||||||
|
xcrun notarytool submit starship.zip --keychain-profile "$KEYCHAIN_ENTRY" --wait
|
||||||
|
|
||||||
|
# Don't think this is actually necessary, but not costly so why not
|
||||||
|
rm starship
|
||||||
|
unzip starship.zip
|
||||||
|
|
||||||
|
# Create the component package
|
||||||
|
echo ">>>> Building Component Package"
|
||||||
|
bash "$script_dir/build_component_package.sh" "starship" "$starship_docs_dir/.vuepress/dist"
|
||||||
|
|
||||||
|
# Create the distribution package
|
||||||
|
echo ">>>> Building Distribution Package"
|
||||||
|
resources_path="$script_dir/pkg_resources"
|
||||||
|
bash "$script_dir/build_distribution_package.sh" "starship-component.pkg" "$resources_path" "$arch"
|
||||||
|
|
||||||
|
# Codesign the package installer
|
||||||
|
productsign --timestamp --sign "$INSTALLATION_KEY_IDENT" starship-unsigned.pkg starship.pkg
|
||||||
|
|
||||||
|
# Notarize the package installer
|
||||||
|
echo ">>>> Submitting .pkg for notarization"
|
||||||
|
xcrun notarytool submit starship.pkg --keychain-profile "$KEYCHAIN_ENTRY" --wait
|
||||||
|
|
||||||
|
# Staple things
|
||||||
|
echo ">>>> Running final steps"
|
||||||
|
xcrun stapler staple starship.pkg
|
||||||
|
|
||||||
|
# Rename to expected name
|
||||||
|
if [ "$pkgname" = "" ]; then
|
||||||
|
version="$(starship_version "$starship_binary")"
|
||||||
|
pkgname="starship-$version-$arch.pkg"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ">>>> Placing final output at $pkgname"
|
||||||
|
mv starship.pkg "$pkgname"
|
|
@ -0,0 +1,90 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Requirements:
|
||||||
|
# - MacOS
|
||||||
|
# - A starship repository with binaries and documentation already built.
|
||||||
|
# Usage: run this script, passing $1 to the repository path. The script assumes
|
||||||
|
# it is being run from within a starship repository if $1 is not provided.
|
||||||
|
|
||||||
|
usage(){
|
||||||
|
echo "Builds a component package for macOS."
|
||||||
|
echo "Assumes that the following items already exist:"
|
||||||
|
echo " - A starship binary which has already been notarized"
|
||||||
|
echo " - Documentation created by \`npm run build\`, usually in a dist"
|
||||||
|
echo " directory at <repo>/docs/.vuepress/dist"
|
||||||
|
echo "Usage: $0 <path-to-starship-binary> <path-to-dist-directory>"
|
||||||
|
}
|
||||||
|
|
||||||
|
script_dir="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||||
|
source "$script_dir/common.sh"
|
||||||
|
|
||||||
|
cleanup_server(){
|
||||||
|
if [[ -n "${server_pid-}" ]]; then
|
||||||
|
echo "Killing HTTP server ($server_pid) to clean up."
|
||||||
|
kill "$server_pid"
|
||||||
|
rm "x86_64-apple-darwin-simple-http-server"
|
||||||
|
else
|
||||||
|
echo "No server found, exiting normally."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$OSTYPE" != 'darwin'* ]]; then
|
||||||
|
error "This script only works on MacOS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${2-undefined}" = "undefined" ]]; then
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
starship_program_file="$1"
|
||||||
|
starship_documentation_dir="$2"
|
||||||
|
|
||||||
|
if [ ! -f "$starship_program_file" ]; then
|
||||||
|
error "Could not find starship binary at $starship_program_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$starship_documentation_dir" ]; then
|
||||||
|
error "Could not find starship documentation at $starship_documentation_dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
pkgdir="$(mktemp -d)"
|
||||||
|
mkdir -p "$pkgdir/usr/local/bin"
|
||||||
|
cp "$starship_program_file" "$pkgdir/usr/local/bin/starship"
|
||||||
|
|
||||||
|
# Now we get to make documentation! Vuepress was not designed to build locally
|
||||||
|
# (too many assumptions about running on an HTTP server), so we do the hackiest
|
||||||
|
# thing imagineable: start an http server, and use wget to make a local mirror.
|
||||||
|
|
||||||
|
# First, we need to install the server. There are several options, but this one
|
||||||
|
# provides prebuilt binaries for MacOS, making it the easiest. (yay rust)
|
||||||
|
server_prog_name="x86_64-apple-darwin-simple-http-server"
|
||||||
|
latest_server_version="$(curl -L -s -H 'Accept: application/json' https://github.com/TheWaWaR/simple-http-server/releases/latest | sed -e 's/.*"tag_name":"\([^"]*\)".*/\1/')"
|
||||||
|
curl -LOk "https://github.com/TheWaWaR/simple-http-server/releases/download/$latest_server_version/$server_prog_name"
|
||||||
|
chmod u+x "$server_prog_name"
|
||||||
|
|
||||||
|
# Next, we build the documentation and serve it via simple-http-server
|
||||||
|
trap cleanup_server INT
|
||||||
|
"./$server_prog_name" --ip 127.0.0.1 --index "$starship_documentation_dir" &
|
||||||
|
server_pid="$!"
|
||||||
|
# Give the server a chance to come online before trying to mirror it
|
||||||
|
echo "Sleeping to give the server a chance to come online..."
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
# Use wget to make a mirror of the site and move it into the package. Not installed
|
||||||
|
# on MacOS by default, but lucky for us, it does exist on GHActions runners.
|
||||||
|
# Wget may return nonzero exit codes even if things were mostly fine (e.g. 404 for
|
||||||
|
# some links on translated pages) so we simply ignore if it has a failure
|
||||||
|
wget --mirror --convert-links --adjust-extension --page-requisites --no-parent 127.0.0.1:8000 &> wget.log || true
|
||||||
|
mkdir -p "$pkgdir/usr/local/share/doc/"
|
||||||
|
mv 127.0.0.1:8000 "$pkgdir/usr/local/share/doc/starship"
|
||||||
|
|
||||||
|
# Technically a race condition here, but very unlikely to hit it in practice.
|
||||||
|
cleanup_server
|
||||||
|
trap - INT
|
||||||
|
|
||||||
|
# Build the component package
|
||||||
|
version="$(starship_version "$starship_program_file")"
|
||||||
|
pkgbuild --identifier com.starshipprompt.starship --version "$version" --root $pkgdir starship-component.pkg
|
|
@ -0,0 +1,67 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
component_package="$1"
|
||||||
|
resources="$2"
|
||||||
|
arch="$3"
|
||||||
|
|
||||||
|
usage(){
|
||||||
|
echo "Builds a distribution package for macOS."
|
||||||
|
echo "Assumes that the following items already exist:"
|
||||||
|
echo " - A starship component package"
|
||||||
|
echo " - Resources in a pkg_resources directory"
|
||||||
|
echo "Usage: $0 <path-to-component-package> <path-to-pkg-resources> <arch>"
|
||||||
|
echo " where arch is one of \"arm64\" or \"x86_64\""
|
||||||
|
}
|
||||||
|
|
||||||
|
script_dir="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||||
|
source "$script_dir/common.sh"
|
||||||
|
|
||||||
|
if [[ "$OSTYPE" != 'darwin'* ]]; then
|
||||||
|
error "This script only works on MacOS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${3-undefined}" = "undefined" ]]; then
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate a distribution file with the appropriate architecture plists
|
||||||
|
if [[ "$arch" == "x86_64" || "$arch" == "x64" ]]; then
|
||||||
|
archplist="$script_dir/x86_64.plist"
|
||||||
|
elif [[ "$arch" == "arm64" || "$arch" == "aarch64" ]]; then
|
||||||
|
archplist="$script_dir/aarch64.plist"
|
||||||
|
else
|
||||||
|
error "Invalid architecture: $arch"
|
||||||
|
fi
|
||||||
|
|
||||||
|
productbuild --synthesize --package starship-component.pkg --product "$archplist" starship_raw.dist
|
||||||
|
|
||||||
|
# A terrible hacky way to insert nodes into XML without needing a full XML parser:
|
||||||
|
# search for a line that matches our opening tag and insert our desired lines after it
|
||||||
|
# Solution taken from https://www.theunixschool.com/2012/06/insert-line-before-or-after-pattern.html
|
||||||
|
|
||||||
|
while read -r line
|
||||||
|
do
|
||||||
|
echo "$line"
|
||||||
|
if echo "$line" | grep -qF '<installer-gui-script '; then
|
||||||
|
echo '<welcome file="welcome.html" mime-type="text-html" />'
|
||||||
|
echo '<license file="license.html" mime-type="text-html" />'
|
||||||
|
echo '<conclusion file="conclusion.html" mime-type="text-html" />'
|
||||||
|
echo '<background file="icon.png" scaling="proportional" alignment="bottomleft"/>'
|
||||||
|
fi
|
||||||
|
done < starship_raw.dist > starship.dist
|
||||||
|
|
||||||
|
# The above script does not correctly take care of the last line. Apply fixup.
|
||||||
|
echo '</installer-gui-script>' >> starship.dist
|
||||||
|
|
||||||
|
echo "Creating distribution package with following distribution file:"
|
||||||
|
cat starship.dist
|
||||||
|
|
||||||
|
echo "Resource directory is $resources"
|
||||||
|
echo "Component package is $component_package"
|
||||||
|
|
||||||
|
# Build the distribution package
|
||||||
|
productbuild --distribution starship.dist --resources "$resources" --package-path "$component_package" starship-unsigned.pkg
|
||||||
|
|
||||||
|
# Clean up the distribution files
|
||||||
|
rm -- *.dist
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
error(){
|
||||||
|
echo "[ERROR]: $1"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
starship_version(){
|
||||||
|
starship_program_file="$1"
|
||||||
|
# Check if this is a relative path: if so, prepend './' to it
|
||||||
|
if [ "$1" = "${1#/}" ]; then
|
||||||
|
starship_program_file="./$starship_program_file"
|
||||||
|
fi
|
||||||
|
if "$starship_program_file" -V 2>&1 > /dev/null; then
|
||||||
|
"$starship_program_file" -V | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+'
|
||||||
|
else
|
||||||
|
# try to get this information from Cargo.toml
|
||||||
|
pushd "$(git rev-parse --show-toplevel)" || true
|
||||||
|
grep '^version = \"\(.*\)\"' Cargo.toml | cut -f 2 -d '"'
|
||||||
|
popd
|
||||||
|
fi
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Install Starship</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<font face="Helvetica Neue" size="4">
|
||||||
|
<p>Starship has been installed!</p>
|
||||||
|
<p>Visit <a href="https://starship.rs">https://starship.rs</a> to get
|
||||||
|
instructions on how to configure your shell to use starship.</p>
|
||||||
|
<p>If you do not have internet access, you can view an offline copy of the
|
||||||
|
the documentation by opening
|
||||||
|
<a href="file:///usr/local/share/doc/starship/index.html">
|
||||||
|
<code>
|
||||||
|
/usr/local/share/doc/starship/index.html.
|
||||||
|
</code>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>Unless you modified the installer, your copy of starship was installed to
|
||||||
|
<code>/usr/local/bin/starship</code>.
|
||||||
|
</p>
|
||||||
|
</font>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>ISC License</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<font face="Helvetica Neue" size="4">
|
||||||
|
<p>ISC License</p>
|
||||||
|
<p>Copyright (c) 2019-2022, Starship Contributors</p>
|
||||||
|
<p>Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.</p>
|
||||||
|
<p>THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.</p>
|
||||||
|
</font>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Install Starship</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<font face="Helvetica Neue" size="4">
|
||||||
|
<p>Starship is the minimal, blazing-fast, and infinitely customizable prompt for any shell!</p>
|
||||||
|
<p>This installer will install Starship on to <code>/usr/local/</code> on your system.</p>
|
||||||
|
<p>After the installation, you will need to modify your shell startup files to
|
||||||
|
use starship.</p>
|
||||||
|
</font>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
|
@ -0,0 +1,263 @@
|
||||||
|
# MacOS Codesigning Scripts
|
||||||
|
|
||||||
|
Well, here we are. The Apple notarization procedure is complex enough that I
|
||||||
|
need an actual pile of scripts and writeup to be able to remember how to do it.
|
||||||
|
|
||||||
|
The basic procedure is as follows:
|
||||||
|
|
||||||
|
- Build code
|
||||||
|
- Build docs
|
||||||
|
- Sign binary with Developer Application ID
|
||||||
|
- Upload binary to notarization service to get notarized
|
||||||
|
- Use code + docs to generate a component package
|
||||||
|
- Use component package to generate a distribution package
|
||||||
|
- Sign distribution package with Developer Installer ID
|
||||||
|
- Upload distribution package to notarization service to get notarized
|
||||||
|
|
||||||
|
Et. voila, you have a notarized distribution package which can be installed.
|
||||||
|
|
||||||
|
I fully anticipate that this procedure will break in the future, so here is the
|
||||||
|
(scant) documentation that I have been able to scrape together on these procedures,
|
||||||
|
along with some commentary on things that I've found and requirements for these
|
||||||
|
scripts.
|
||||||
|
|
||||||
|
You will need XCode installed.
|
||||||
|
|
||||||
|
## Short-form Command Line Invocation
|
||||||
|
|
||||||
|
If you have the prerequisites set up (including the environment variables as
|
||||||
|
described below, built docs, and built release binary), you can generate the
|
||||||
|
package file with the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
./install/macos_packages/build_and_notarize.sh target/release/starship docs x64
|
||||||
|
```
|
||||||
|
|
||||||
|
or `arm64` if building on Apple silicon.
|
||||||
|
|
||||||
|
## Setting Up Credentials
|
||||||
|
|
||||||
|
### Apple Developer Account
|
||||||
|
|
||||||
|
In order to get the signing keys, you need to have a developer account. You can
|
||||||
|
buy one at https://developer.apple.com/programs/ for $100 a year (at time of
|
||||||
|
writing).
|
||||||
|
|
||||||
|
There is no other way to acquire an account, which is needed to obtain
|
||||||
|
non-self-signed keys and to be able to notarize files.
|
||||||
|
|
||||||
|
### Signing Keys
|
||||||
|
|
||||||
|
To generate the signing keys, I went through the [XcodeGUI](https://help.apple.com/xcode/mac/current/#/dev154b28f09), though there are
|
||||||
|
several other methods to do this. You will need at least one Application signing
|
||||||
|
key and one Installer signing key.
|
||||||
|
|
||||||
|
To check what signing keys are available, you can use the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
security find-identity -p basic -v
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notarization Credentials
|
||||||
|
|
||||||
|
To be able to notarize objects, you will need an app-specific password. You will
|
||||||
|
need to set it up using the instructions [on this page](https://support.apple.com/en-us/HT204397).
|
||||||
|
You will also need your team ID, which can be found at https://developer.apple.com/account/#/membership
|
||||||
|
(if it goes to the home page, click on "Membership" on the left panel), and your
|
||||||
|
Apple ID (usually an email address).
|
||||||
|
|
||||||
|
If you want to enter everything manually, most commands that require these values
|
||||||
|
accept the `--apple-id`, `--team-id`, and `--password` flags. However, I find it
|
||||||
|
simpler to store the credentials in the keychain. You can do so with the following
|
||||||
|
command:
|
||||||
|
|
||||||
|
```
|
||||||
|
xcrun notarytool store-credentials "<AUTH_ITEM_NAME>" --apple-id "<apple-id>" --password "<password>" --team-id "<team-id>"
|
||||||
|
```
|
||||||
|
|
||||||
|
where `<AUTH_ITEM_NAME>` is a name you will use later to refer to the credentials,
|
||||||
|
and the other three items are the Apple ID, the Team ID, and the app-specific password,
|
||||||
|
respectively. For the rest of this document, I will assume that its value is
|
||||||
|
`AC_PASSWORD` for compatibility with Apple's website, though you may choose
|
||||||
|
whatever you like.
|
||||||
|
|
||||||
|
### Script Assumptions
|
||||||
|
|
||||||
|
The scripts in this directory assume that the signing keys and the notarization
|
||||||
|
credentials are unlocked and available within a specific keychain file, stored
|
||||||
|
in a file at `$RUNNER_TEMP/$KEYCHAIN_FILENAME`. Additionally, it assumes that
|
||||||
|
the `AUTH_ITEM_NAME` used to refer to the notarization credentials is found in
|
||||||
|
the environment under the variable `KEYCHAIN_ENTRY`.
|
||||||
|
|
||||||
|
The CI environment ensures that the keychain file exists at the appropriate
|
||||||
|
locations and is destroyed after use. If you are running these scripts locally,
|
||||||
|
the values that correspond to what Apple uses in their tutorials are:
|
||||||
|
|
||||||
|
```
|
||||||
|
KEYCHAIN_ENTRY=AC_PASSWORD # Or whatever you picked for <AUTH_ITEM_NAME> above
|
||||||
|
RUNNER_TEMP=~/Library/Keychains
|
||||||
|
KEYCHAIN_FILENAME=login.keychain
|
||||||
|
```
|
||||||
|
|
||||||
|
Note to developers: because the keychain file may be a user's personal keychain,
|
||||||
|
you MUST NEVER WRITE TO THE KEYCHAIN FILE in these scripts. On the CI, CI actions
|
||||||
|
will ensure that the keychain file is shredded after use.
|
||||||
|
|
||||||
|
## Codesigning a Binary
|
||||||
|
|
||||||
|
This is actually fairly simple. Run
|
||||||
|
|
||||||
|
```
|
||||||
|
codesign --timestamp --sign "<Key ID>" --verbose -f -o runtime <binary>
|
||||||
|
```
|
||||||
|
|
||||||
|
to sign the binary file. `--timestamp` is not required for signing, but will be
|
||||||
|
required for notarization. `<Key ID>` can be one of two things: the name of the
|
||||||
|
signing key (on the right of `security find-identity -p basic -v`), or the key
|
||||||
|
hash (the hex string on the left of the command).
|
||||||
|
|
||||||
|
Usually you can use name of the key, but if you have multiple keys like me, you
|
||||||
|
may need to use the hex string to specify.
|
||||||
|
|
||||||
|
## Notarizing a Binary
|
||||||
|
|
||||||
|
Once the binary has been signed, you need to package it into a .zip file in order
|
||||||
|
to be able to send it to Apple for notarization. The simplest way to do this is
|
||||||
|
to run `zip <archive.zip> <binary>`.
|
||||||
|
|
||||||
|
Then, run `xcrun notarytool submit <archive.zip> --keychain-profile "AC_PASSWORD" --wait`
|
||||||
|
to submit the binary for notarization. The `--wait` flag will cause the tool to
|
||||||
|
block until the notarialization is complete. If you want to be able to leave and
|
||||||
|
check the results later, omit `--wait` (though starship notarization usually takes
|
||||||
|
no more than 60s).
|
||||||
|
|
||||||
|
Finally, you should check the submission logs. To get a record of all notarization
|
||||||
|
attempts, run
|
||||||
|
|
||||||
|
```
|
||||||
|
xcrun notarytool history --keychain-profile "AC_PASSWORD"
|
||||||
|
```
|
||||||
|
|
||||||
|
Find the `id` of the attempt you wish to view, then run one of these commmands:
|
||||||
|
|
||||||
|
```
|
||||||
|
xcrun notarytool info <run-id> --keychain-profile "AC_PASSWORD"
|
||||||
|
xcrun notarytool log <run-id> --keychain-profile "AC_PASSWORD"
|
||||||
|
```
|
||||||
|
|
||||||
|
The `log` command downloads a JSON log of the notarization attempt, and can reveal
|
||||||
|
warnings that should be fixed before the next submission.
|
||||||
|
|
||||||
|
Additional details on the notarization process can be found at https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/customizing_the_notarization_workflow.
|
||||||
|
Note that while Apple has a lot of requirements on their pages, including stuff
|
||||||
|
like Hardened Runtime requirements and listing entitlements, as far as I can tell,
|
||||||
|
starship does not require any of these even though we do things like send
|
||||||
|
notifications and access the network via an HTTP client. Nonetheless, I'm
|
||||||
|
linking the [entitlements page](https://developer.apple.com/documentation/bundleresources/entitlements)
|
||||||
|
here in case it becomes important later.
|
||||||
|
|
||||||
|
## Creating a Component Package
|
||||||
|
|
||||||
|
Since I'm only dealing with one binary, we will make one Component package and
|
||||||
|
one Distribution package. Surprisingly, the flat package (.pkg) format is not
|
||||||
|
documented by Apple. [This guide](https://matthew-brett.github.io/docosx/flat_packages.html)
|
||||||
|
and many of the links within it are the best documentation available on the subject.
|
||||||
|
|
||||||
|
To build a component package, we first need to create a temporary directory and
|
||||||
|
create a pseudo-filesystem within it (similar to makepkg on Arch). For example,
|
||||||
|
if we place the directory at `$TEMP_DIR/usr/local/bin/starship`, the binary
|
||||||
|
will be installed at `/usr/local/bin/starship` once the installer runs.
|
||||||
|
|
||||||
|
An aside on docs: We would also like to include documentation in the pkg.
|
||||||
|
Unfortunately, Vuepress currently cannot build with relative paths, and any
|
||||||
|
attempt at hacking this in seems to create even more problems. Instead, the
|
||||||
|
scripts do the dumbest thing imaginable: build the documentation, serve it with
|
||||||
|
a simple HTTP server, and then use `wget` to make a local copy which can be
|
||||||
|
viewed offline.
|
||||||
|
|
||||||
|
Once everything is placed in the correct locations, we can run the following
|
||||||
|
command to generate the component package:
|
||||||
|
|
||||||
|
```
|
||||||
|
pkgbuild --identifier com.starshipprompt.starship --version "<version>" --root <pkgdir> output.pkg
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notarizing the Component Package (and why we don't need to)
|
||||||
|
|
||||||
|
Fortunately for us, Apple has confirmed that we only need to notarize the
|
||||||
|
[outermost installer mechanism](https://developer.apple.com/forums/thread/122045).
|
||||||
|
|
||||||
|
Therefore, if we are sending the component package on its own, we should notarize
|
||||||
|
it now. However, for starship, we will bundle this into a distribution package,
|
||||||
|
so we don't need to notarize this pkg file.
|
||||||
|
|
||||||
|
## Creating a Distribution Package
|
||||||
|
|
||||||
|
To create a distribution, we do the following steps:
|
||||||
|
|
||||||
|
- Use `productbuild` to generate a skeleton distribution file.
|
||||||
|
- Insert custom welcome/license/conclusion and icon files into the installer.
|
||||||
|
- Build the installer with `productbuild`.
|
||||||
|
|
||||||
|
I have elected not to make a fat binary due to concerns over startup cost, so
|
||||||
|
there are two .plist files that can be used to specify the architecture required.
|
||||||
|
|
||||||
|
## Signing the Distribution package
|
||||||
|
|
||||||
|
This is also fairly simple, and analagous to signing the binary.
|
||||||
|
|
||||||
|
```
|
||||||
|
productsign --timestamp --sign "<Key ID>" <input.pkg> <output.pkg>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notarizing the Distribution Package
|
||||||
|
|
||||||
|
Also analagous to notarizing the binary. We run
|
||||||
|
|
||||||
|
```
|
||||||
|
xcrun notarytool submit <package.pkg> --keychain-profile "AC_PASSWORD" --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
and also check the submission logs.
|
||||||
|
|
||||||
|
Note: you may need to enter your password a ridiculous number of times (like 4+)
|
||||||
|
in order to successfully notarize this.
|
||||||
|
|
||||||
|
## Stapling the Result
|
||||||
|
|
||||||
|
Finally, we staple the notarization ticket to the package, ensuring that anyone
|
||||||
|
who downloads the file can see that the installer was notarized:
|
||||||
|
|
||||||
|
```
|
||||||
|
xcrun stapler staple <package>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that `.dmg`, `.app`, and `.pkg` files can be stapled, but `.zip` and
|
||||||
|
binary files cannot. Distributing the latter files alone will require that the
|
||||||
|
installing computer can access the internet to verify notarization of the app.
|
||||||
|
|
||||||
|
## Putting It All Together
|
||||||
|
|
||||||
|
If you don't want to run these commands, a full workflow is available in
|
||||||
|
`build_and_notarize` script. Check the documentation at the top of the script
|
||||||
|
for environment variables and arguments that need to be set--it is a fairly
|
||||||
|
complicated script, but this is a fairly complicated procedure.
|
||||||
|
|
||||||
|
# Testing Notarization
|
||||||
|
|
||||||
|
To test if a particular item is notarized, run one of the following commands:
|
||||||
|
|
||||||
|
```
|
||||||
|
codesign --test-requirement="=notarized" --verify --verbose <file>
|
||||||
|
spctl -a -vvv -t install <file>
|
||||||
|
```
|
||||||
|
|
||||||
|
# External Links
|
||||||
|
|
||||||
|
https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution
|
||||||
|
|
||||||
|
https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/customizing_the_notarization_workflow
|
||||||
|
|
||||||
|
https://github.com/akeru-inc/xcnotary
|
||||||
|
|
||||||
|
https://www.reddit.com/r/rust/comments/q8r90b/notarization_of_rust_binary_for_distribution_on/
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?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>arch</key>
|
||||||
|
<array>
|
||||||
|
<string>x86_64</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
Loading…
Reference in New Issue