feather/contrib/guix/guix-attest
tobtoht 725ad63210
Some checks failed
ci/gh-actions/build / build-ubuntu-without-scanner (push) Has been cancelled
ci/gh-actions/guix / cache-sources (push) Has been cancelled
ci/gh-actions/guix / aarch64-linux-gnu (push) Has been cancelled
ci/gh-actions/guix / arm-linux-gnueabihf (push) Has been cancelled
ci/gh-actions/guix / arm64-apple-darwin (push) Has been cancelled
ci/gh-actions/guix / riscv64-linux-gnu (push) Has been cancelled
ci/gh-actions/guix / x86_64-apple-darwin (push) Has been cancelled
ci/gh-actions/guix / x86_64-linux-gnu.no-tor-bundle (push) Has been cancelled
ci/gh-actions/guix / x86_64-linux-gnu.pack (push) Has been cancelled
ci/gh-actions/guix / x86_64-linux-gnu (push) Has been cancelled
ci/gh-actions/guix / x86_64-w64-mingw32.installer (push) Has been cancelled
ci/gh-actions/guix / x86_64-w64-mingw32 (push) Has been cancelled
ci/gh-actions/guix / bundle-logs (push) Has been cancelled
ci/gh-actions/guix / codesigning (map[target:x86_64-w64-mingw32.installer]) (push) Has been cancelled
ci/gh-actions/guix / codesigning (map[target:x86_64-w64-mingw32]) (push) Has been cancelled
build: add make convenience wrapper for guix scripts
2024-11-04 18:19:56 +01:00

304 lines
8.1 KiB
Bash
Executable file

#!/usr/bin/env bash
export LC_ALL=C
set -e -o pipefail
# Source the common prelude, which:
# 1. Checks if we're at the top directory of the Feather Wallet repository
# 2. Defines a few common functions and variables
#
# shellcheck source=libexec/prelude.bash
source "$(dirname "${BASH_SOURCE[0]}")/libexec/prelude.bash"
###################
## Sanity Checks ##
###################
################
# Required non-builtin commands should be invokable
################
check_tools cat env basename mkdir diff sort
if [ -z "$NO_SIGN" ]; then
# make it possible to override the gpg binary
GPG=${GPG:-gpg}
# $GPG can contain extra arguments passed to the binary
# so let's check only the existence of arg[0]
# shellcheck disable=SC2206
GPG_ARRAY=($GPG)
check_tools "${GPG_ARRAY[0]}"
fi
################
# Required env vars should be non-empty
################
cmd_usage() {
cat <<EOF
Synopsis:
env GUIX_SIGS_REPO=<path/to/feather-sigs> \\
SIGNER=GPG_KEY_NAME[=SIGNER_NAME] \\
[ NO_SIGN=1 ]
./contrib/guix/guix-attest
Example w/o overriding signing name:
env GUIX_SIGS_REPO=/home/user/feather-sigs \\
SIGNER=achow101 \\
./contrib/guix/guix-attest
Example overriding signing name:
env GUIX_SIGS_REPO=/home/user/feather-sigs \\
SIGNER=0x96AB007F1A7ED999=dongcarl \\
./contrib/guix/guix-attest
Example w/o signing, just creating SHA256SUMS:
env GUIX_SIGS_REPO=/home/user/feather-sigs \\
SIGNER=achow101 \\
NO_SIGN=1 \\
./contrib/guix/guix-attest
EOF
}
if [ -z "${GUIX_SIGS_REPO}" ]; then
echo "[HINT] Fork and clone the feather-sigs repo, if you haven't already:"
echo "https://github.com/feather-wallet/feather-sigs"
echo ""
printf "Enter path to 'feather-sigs' repo: "
read -r repo
if [ ! -d "${repo}" ]; then
echo "ERR: directory does not exist"
exit 1
fi
export GUIX_SIGS_REPO="$repo"
wizard=1
fi
if [ -z "${SIGNER}" ]; then
printf "Enter your GitHub username: "
read -r signer
if [ -z "$signer" ]; then
echo "ERR: signer name can't be empty"
exit 1
fi
echo ""
echo "[HINT] To find your GPG fingerprint use:"
echo "gpg --list-secret-keys --keyid-format=long"
echo "It should look like: E87BD921CDD885C9D78A38C5E45B10DD027D2472"
echo ""
printf "Enter fingerprint of your GPG key: "
read -r fingerprint
export SIGNER="${fingerprint}=${signer}"
wizard=1
fi
if [ -n "$wizard" ]; then
echo ""
echo "Next time, invoke this command as:"
echo "env GUIX_SIGS_REPO=${GUIX_SIGS_REPO} SIGNER=${SIGNER} make attest"
echo ""
fi
################
# GUIX_SIGS_REPO should exist as a directory
################
if [ ! -d "$GUIX_SIGS_REPO" ]; then
cat << EOF
ERR: The specified GUIX_SIGS_REPO is not an existent directory:
'$GUIX_SIGS_REPO'
Hint: Please clone the feather-sigs repository and point to it with the
GUIX_SIGS_REPO environment variable.
EOF
cmd_usage
exit 1
fi
################
# The key specified in SIGNER should be usable
################
IFS='=' read -r gpg_key_name signer_name <<< "$SIGNER"
if [ -z "${signer_name}" ]; then
signer_name="$gpg_key_name"
fi
if [ -z "$NO_SIGN" ] && ! ${GPG} --dry-run --list-secret-keys "${gpg_key_name}" >/dev/null 2>&1; then
echo "ERR: GPG can't seem to find any key named '${gpg_key_name}'"
exit 1
fi
################
# We should be able to find at least one output
################
echo "Looking for build output SHA256SUMS fragments in ${LOGDIR_BASE}"
shopt -s nullglob
sha256sum_fragments=( "$LOGDIR_BASE"/*/SHA256SUMS.part ) # This expands to an array of directories...
shopt -u nullglob
noncodesigned_fragments=()
codesigned_fragments=()
if (( ${#sha256sum_fragments[@]} )); then
echo "Found build output SHA256SUMS fragments:"
for logdir in "${sha256sum_fragments[@]}"; do
echo " '$logdir'"
case "$logdir" in
"$LOGDIR_BASE"/*-codesigned/SHA256SUMS.part)
codesigned_fragments+=("$logdir")
;;
*)
noncodesigned_fragments+=("$logdir")
;;
esac
done
echo
else
echo "ERR: Could not find any build output SHA256SUMS fragments in ${LOGDIR_BASE}"
exit 1
fi
##############
## Attest ##
##############
# Usage: out_name $logdir
#
# HOST: The output directory being attested
#
out_name() {
basename "$(dirname "$1")"
}
shasum_already_exists() {
cat <<EOF
--
ERR: An ${1} file already exists for '${VERSION}' and attests
differently. You likely previously attested to a partial build (e.g. one
where you specified the HOST environment variable).
See the diff above for more context.
Hint: You may wish to remove the existing attestations and their signatures by
invoking:
rm '${PWD}/${1}'{,.asc}
Then try running this script again.
EOF
}
echo "Attesting to build outputs for version: '${VERSION}'"
echo ""
# Given a SHA256SUMS file as stdin that has lines like:
# 0ba536819b221a91d3d42e978be016aac918f40984754d74058aa0c921cd3ea6 a/b/d/c/d/s/feather-2.5.0-riscv64-linux-gnu.tar.gz
# ...
#
# Replace each line's file name with its basename:
# 0ba536819b221a91d3d42e978be016aac918f40984754d74058aa0c921cd3ea6 feather-2.5.0-riscv64-linux-gnu.tar.gz
# ...
#
basenameify_SHA256SUMS() {
sed -E 's@(^[[:xdigit:]]{64}[[:space:]]+).+/([^/]+$)@\1\2@'
}
outsigdir="$GUIX_SIGS_REPO/$VERSION/$signer_name"
mkdir -p "$outsigdir"
(
cd "$outsigdir"
temp_noncodesigned="$(mktemp)"
trap 'rm -rf -- "$temp_noncodesigned"' EXIT
if (( ${#noncodesigned_fragments[@]} )); then
cat "${noncodesigned_fragments[@]}" \
| sort -u \
| basenameify_SHA256SUMS \
| sort -k2 \
> "$temp_noncodesigned"
if [ -e noncodesigned.SHA256SUMS ]; then
# The SHA256SUMS already exists, make sure it's exactly what we
# expect, error out if not
if diff -u noncodesigned.SHA256SUMS "$temp_noncodesigned"; then
echo "A noncodesigned.SHA256SUMS file already exists for '${VERSION}' and is up-to-date."
else
shasum_already_exists noncodesigned.SHA256SUMS
exit 1
fi
else
mv "$temp_noncodesigned" noncodesigned.SHA256SUMS
fi
else
echo "ERR: No noncodesigned outputs found for '${VERSION}', exiting..."
exit 1
fi
temp_all="$(mktemp)"
trap 'rm -rf -- "$temp_all"' EXIT
if (( ${#codesigned_fragments[@]} )); then
# Note: all.SHA256SUMS attests to all of $sha256sum_fragments, but is
# not needed if there are no $codesigned_fragments
cat "${sha256sum_fragments[@]}" \
| sort -u \
| basenameify_SHA256SUMS \
| sort -k2 \
> "$temp_all"
if [ -e all.SHA256SUMS ]; then
# The SHA256SUMS already exists, make sure it's exactly what we
# expect, error out if not
if diff -u all.SHA256SUMS "$temp_all"; then
echo "An all.SHA256SUMS file already exists for '${VERSION}' and is up-to-date."
else
shasum_already_exists all.SHA256SUMS
exit 1
fi
else
mv "$temp_all" all.SHA256SUMS
fi
else
# It is fine to have the codesigned outputs be missing (perhaps the
# detached codesigs have not been published yet), just print a log
# message instead of erroring out
echo "INFO: No codesigned outputs found for '${VERSION}', skipping..."
fi
if [ -z "$NO_SIGN" ]; then
echo "Signing SHA256SUMS to produce SHA256SUMS.asc"
for i in *.SHA256SUMS; do
if [ ! -e "$i".asc ]; then
${GPG} --detach-sign \
--digest-algo sha256 \
--local-user "$gpg_key_name" \
--armor \
--output "$i".asc "$i"
else
echo "Signature already there"
fi
done
else
echo "Not signing SHA256SUMS as \$NO_SIGN is not empty"
fi
echo ""
)