summaryrefslogtreecommitdiffstats
path: root/install
diff options
context:
space:
mode:
authorKevin Song <4605384+chipbuster@users.noreply.github.com>2022-02-27 15:58:28 -0600
committerGitHub <noreply@github.com>2022-02-27 15:58:28 -0600
commit955a0f7a3399d089f967a0be3f08b3e62c1c796f (patch)
tree549cb601febd1d15cea714e86dac253d2e4070fd /install
parent4369c92d4033c09ff411771e24c0161d713b7c64 (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.plist10
-rw-r--r--install/macos_packages/build_and_notarize.sh115
-rw-r--r--install/macos_packages/build_component_package.sh90
-rw-r--r--install/macos_packages/build_distribution_package.sh67
-rw-r--r--install/macos_packages/common.sh22
-rw-r--r--install/macos_packages/pkg_resources/English.lproj/conclusion.html28
-rw-r--r--install/macos_packages/pkg_resources/English.lproj/license.html26
-rw-r--r--install/macos_packages/pkg_resources/English.lproj/welcome.html18
-rw-r--r--install/macos_packages/pkg_resources/icon.pngbin0 -> 58035 bytes
-rw-r--r--install/macos_packages/readme.md263
-rw-r--r--install/macos_packages/x86_64.plist10
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 &quot;AS IS&quot; 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
new file mode 100644
index 000000000..4d1690811
--- /dev/null
+++ b/install/macos_packages/pkg_resources/icon.png
Binary files differ
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