diff options
author | Kevin Song <4605384+chipbuster@users.noreply.github.com> | 2022-02-27 15:58:28 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-27 15:58:28 -0600 |
commit | 955a0f7a3399d089f967a0be3f08b3e62c1c796f (patch) | |
tree | 549cb601febd1d15cea714e86dac253d2e4070fd /install | |
parent | 4369c92d4033c09ff411771e24c0161d713b7c64 (diff) |
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
Diffstat (limited to 'install')
-rw-r--r-- | install/macos_packages/aarch64.plist | 10 | ||||
-rw-r--r-- | install/macos_packages/build_and_notarize.sh | 115 | ||||
-rw-r--r-- | install/macos_packages/build_component_package.sh | 90 | ||||
-rw-r--r-- | install/macos_packages/build_distribution_package.sh | 67 | ||||
-rw-r--r-- | install/macos_packages/common.sh | 22 | ||||
-rw-r--r-- | install/macos_packages/pkg_resources/English.lproj/conclusion.html | 28 | ||||
-rw-r--r-- | install/macos_packages/pkg_resources/English.lproj/license.html | 26 | ||||
-rw-r--r-- | install/macos_packages/pkg_resources/English.lproj/welcome.html | 18 | ||||
-rw-r--r-- | install/macos_packages/pkg_resources/icon.png | bin | 0 -> 58035 bytes | |||
-rw-r--r-- | install/macos_packages/readme.md | 263 | ||||
-rw-r--r-- | install/macos_packages/x86_64.plist | 10 |
11 files changed, 649 insertions, 0 deletions
diff --git a/install/macos_packages/aarch64.plist b/install/macos_packages/aarch64.plist new file mode 100644 index 000000000..2b7fc4465 --- /dev/null +++ b/install/macos_packages/aarch64.plist @@ -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>
\ No newline at end of file diff --git a/install/macos_packages/build_and_notarize.sh b/install/macos_packages/build_and_notarize.sh new file mode 100644 index 000000000..1900ed98c --- /dev/null +++ b/install/macos_packages/build_and_notarize.sh @@ -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"
\ No newline at end of file diff --git a/install/macos_packages/build_component_package.sh b/install/macos_packages/build_component_package.sh new file mode 100644 index 000000000..000c08f66 --- /dev/null +++ b/install/macos_packages/build_component_package.sh @@ -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
\ No newline at end of file diff --git a/install/macos_packages/build_distribution_package.sh b/install/macos_packages/build_distribution_package.sh new file mode 100644 index 000000000..54b4ef89d --- /dev/null +++ b/install/macos_packages/build_distribution_package.sh @@ -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
\ No newline at end of file diff --git a/install/macos_packages/common.sh b/install/macos_packages/common.sh new file mode 100644 index 000000000..9a9c8503d --- /dev/null +++ b/install/macos_packages/common.sh @@ -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 +} diff --git a/install/macos_packages/pkg_resources/English.lproj/conclusion.html b/install/macos_packages/pkg_resources/English.lproj/conclusion.html new file mode 100644 index 000000000..57831f780 --- /dev/null +++ b/install/macos_packages/pkg_resources/English.lproj/conclusion.html @@ -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>
\ No newline at end of file diff --git a/install/macos_packages/pkg_resources/English.lproj/license.html b/install/macos_packages/pkg_resources/English.lproj/license.html new file mode 100644 index 000000000..f446f65e4 --- /dev/null +++ b/install/macos_packages/pkg_resources/English.lproj/license.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>
\ No newline at end of file diff --git a/install/macos_packages/pkg_resources/English.lproj/welcome.html b/install/macos_packages/pkg_resources/English.lproj/welcome.html new file mode 100644 index 000000000..e427769b2 --- /dev/null +++ b/install/macos_packages/pkg_resources/English.lproj/welcome.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>
\ No newline at end of file diff --git a/install/macos_packages/pkg_resources/icon.png b/install/macos_packages/pkg_resources/icon.png Binary files differnew file mode 100644 index 000000000..4d1690811 --- /dev/null +++ b/install/macos_packages/pkg_resources/icon.png diff --git a/install/macos_packages/readme.md b/install/macos_packages/readme.md new file mode 100644 index 000000000..c56f84c33 --- /dev/null +++ b/install/macos_packages/readme.md @@ -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/ diff --git a/install/macos_packages/x86_64.plist b/install/macos_packages/x86_64.plist new file mode 100644 index 000000000..535b143d6 --- /dev/null +++ b/install/macos_packages/x86_64.plist @@ -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>
\ No newline at end of file |