mirror of
https://github.com/feather-wallet/feather.git
synced 2025-01-18 16:54:33 +00:00
build: windows codesigning
This commit is contained in:
parent
c033718956
commit
d877523cce
4 changed files with 447 additions and 5 deletions
|
@ -221,8 +221,8 @@ mkdir -p "$outsigdir"
|
|||
# not needed if there are no $codesigned_fragments
|
||||
cat "${sha256sum_fragments[@]}" \
|
||||
| sort -u \
|
||||
| sort -k2 \
|
||||
| basenameify_SHA256SUMS \
|
||||
| sort -k2 \
|
||||
> "$temp_all"
|
||||
if [ -e all.SHA256SUMS ]; then
|
||||
# The SHA256SUMS already exists, make sure it's exactly what we
|
||||
|
|
327
contrib/guix/guix-codesign
Executable file
327
contrib/guix/guix-codesign
Executable file
|
@ -0,0 +1,327 @@
|
|||
#!/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 invocable
|
||||
################
|
||||
|
||||
check_tools cat mkdir git guix
|
||||
|
||||
################
|
||||
# Required env vars should be non-empty
|
||||
################
|
||||
|
||||
cmd_usage() {
|
||||
cat <<EOF
|
||||
Synopsis:
|
||||
|
||||
env GUIX_SIGS_REPO=<path/to/feather-sigs> \\
|
||||
./contrib/guix/guix-codesign
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
if [ -z "$GUIX_SIGS_REPO" ]; then
|
||||
cmd_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
################
|
||||
# GUIX_BUILD_OPTIONS should be empty
|
||||
################
|
||||
#
|
||||
# GUIX_BUILD_OPTIONS is an environment variable recognized by guix commands that
|
||||
# can perform builds. This seems like what we want instead of
|
||||
# ADDITIONAL_GUIX_COMMON_FLAGS, but the value of GUIX_BUILD_OPTIONS is actually
|
||||
# _appended_ to normal command-line options. Meaning that they will take
|
||||
# precedence over the command-specific ADDITIONAL_GUIX_<CMD>_FLAGS.
|
||||
#
|
||||
# This seems like a poor user experience. Thus we check for GUIX_BUILD_OPTIONS's
|
||||
# existence here and direct users of this script to use our (more flexible)
|
||||
# custom environment variables.
|
||||
if [ -n "$GUIX_BUILD_OPTIONS" ]; then
|
||||
cat << EOF
|
||||
Error: Environment variable GUIX_BUILD_OPTIONS is not empty:
|
||||
'$GUIX_BUILD_OPTIONS'
|
||||
|
||||
Unfortunately this script is incompatible with GUIX_BUILD_OPTIONS, please unset
|
||||
GUIX_BUILD_OPTIONS and use ADDITIONAL_GUIX_COMMON_FLAGS to set build options
|
||||
across guix commands or ADDITIONAL_GUIX_<CMD>_FLAGS to set build options for a
|
||||
specific guix command.
|
||||
|
||||
See contrib/guix/README.md for more details.
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
################
|
||||
# The codesignature git worktree should not be dirty
|
||||
################
|
||||
|
||||
if ! git -C "$GUIX_SIGS_REPO" diff-index --quiet HEAD -- && [ -z "$FORCE_DIRTY_WORKTREE" ]; then
|
||||
cat << EOF
|
||||
ERR: The DETACHED CODESIGNATURE git worktree is dirty, which may lead to broken builds.
|
||||
|
||||
Aborting...
|
||||
|
||||
Hint: To make your git worktree clean, You may want to:
|
||||
1. Commit your changes,
|
||||
2. Stash your changes, or
|
||||
3. Set the 'FORCE_DIRTY_WORKTREE' environment variable if you insist on
|
||||
using a dirty worktree
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
################
|
||||
# Build directories should not exist
|
||||
################
|
||||
|
||||
# Default to building for all supported HOSTs (overridable by environment)
|
||||
export HOSTS="${HOSTS:-x86_64-w64-mingw32 x86_64-w64-mingw32.installer}"
|
||||
|
||||
# Usage: distsrc_for_host HOST
|
||||
#
|
||||
# HOST: The current platform triple we're building for
|
||||
#
|
||||
distsrc_for_host() {
|
||||
echo "${DISTSRC_BASE}/build/distsrc-${VERSION}-${1}-codesigned"
|
||||
}
|
||||
|
||||
# Accumulate a list of build directories that already exist...
|
||||
hosts_distsrc_exists=""
|
||||
for host in $HOSTS; do
|
||||
if [ -e "$(distsrc_for_host "$host")" ]; then
|
||||
hosts_distsrc_exists+=" ${host}"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$hosts_distsrc_exists" ]; then
|
||||
# ...so that we can print them out nicely in an error message
|
||||
cat << EOF
|
||||
ERR: Build directories for this commit already exist for the following platform
|
||||
triples you're attempting to build, probably because of previous builds.
|
||||
Please remove, or otherwise deal with them prior to starting another build.
|
||||
|
||||
Aborting...
|
||||
|
||||
Hint: To blow everything away, you may want to use:
|
||||
|
||||
$ ./contrib/guix/guix-clean
|
||||
|
||||
Specifically, this will remove all files without an entry in the index,
|
||||
excluding the SDK directory, the depends download cache, the depends built
|
||||
packages cache, the garbage collector roots for Guix environments, and the
|
||||
output directory.
|
||||
EOF
|
||||
for host in $hosts_distsrc_exists; do
|
||||
echo " ${host} '$(distsrc_for_host "$host")'"
|
||||
done
|
||||
exit 1
|
||||
else
|
||||
mkdir -p "$DISTSRC_BASE"
|
||||
fi
|
||||
|
||||
|
||||
################
|
||||
# Unsigned files SHOULD exist
|
||||
################
|
||||
|
||||
# Usage: outdir_for_host HOST SUFFIX
|
||||
#
|
||||
# HOST: The current platform triple we're building for
|
||||
#
|
||||
outdir_for_host() {
|
||||
echo "${OUTDIR_BASE}/${1}${2:+-${2}}"
|
||||
}
|
||||
|
||||
# Usage: logdir_for_host HOST SUFFIX
|
||||
#
|
||||
# HOST: The current platform triple we're building for
|
||||
#
|
||||
logdir_for_host() {
|
||||
echo "${LOGDIR_BASE}/${1}${2:+-${2}}"
|
||||
}
|
||||
|
||||
unsigned_file_for_host() {
|
||||
case "$1" in
|
||||
*mingw32.installer)
|
||||
echo "$(outdir_for_host "$1")/FeatherWalletSetup-${VERSION}-unsigned.exe"
|
||||
;;
|
||||
*mingw32*)
|
||||
echo "$(outdir_for_host "$1")/${DISTNAME}-unsigned.exe"
|
||||
;;
|
||||
*)
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Accumulate a list of build directories that already exist...
|
||||
hosts_file_tarball_missing=""
|
||||
for host in $HOSTS; do
|
||||
if [ ! -e "$(unsigned_file_for_host "$host")" ]; then
|
||||
hosts_file_tarball_missing+=" ${host}"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$hosts_file_tarball_missing" ]; then
|
||||
# ...so that we can print them out nicely in an error message
|
||||
cat << EOF
|
||||
ERR: Unsigned files do not exist
|
||||
...
|
||||
|
||||
EOF
|
||||
for host in $hosts_file_tarball_missing; do
|
||||
echo " ${host} '$(unsigned_file_for_host "$host")'"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
################
|
||||
# Check that we can connect to the guix-daemon
|
||||
################
|
||||
|
||||
cat << EOF
|
||||
Checking that we can connect to the guix-daemon...
|
||||
|
||||
Hint: If this hangs, you may want to try turning your guix-daemon off and on
|
||||
again.
|
||||
|
||||
EOF
|
||||
if ! guix gc --list-failures > /dev/null; then
|
||||
cat << EOF
|
||||
|
||||
ERR: Failed to connect to the guix-daemon, please ensure that one is running and
|
||||
reachable.
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Developer note: we could use `guix repl` for this check and run:
|
||||
#
|
||||
# (import (guix store)) (close-connection (open-connection))
|
||||
#
|
||||
# However, the internal API is likely to change more than the CLI invocation
|
||||
|
||||
|
||||
#########
|
||||
# SETUP #
|
||||
#########
|
||||
|
||||
# Determine the maximum number of jobs to run simultaneously (overridable by
|
||||
# environment)
|
||||
JOBS="${JOBS:-$(nproc)}"
|
||||
|
||||
# Determine the reference time used for determinism (overridable by environment)
|
||||
SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(git -c log.showSignature=false log --format=%at -1)}"
|
||||
|
||||
# Make sure an output directory exists for our builds
|
||||
OUTDIR_BASE="${OUTDIR_BASE:-${VERSION_BASE}/output}"
|
||||
mkdir -p "$OUTDIR_BASE"
|
||||
|
||||
# Usage: profiledir_for_host HOST SUFFIX
|
||||
#
|
||||
# HOST: The current platform triple we're building for
|
||||
#
|
||||
profiledir_for_host() {
|
||||
echo "${PROFILES_BASE}/${1}${2:+-${2}}"
|
||||
}
|
||||
|
||||
#########
|
||||
# BUILD #
|
||||
#########
|
||||
|
||||
# Function to be called when codesigning for host ${1} and the user interrupts
|
||||
# the codesign
|
||||
int_trap() {
|
||||
cat << EOF
|
||||
** INT received while codesigning ${1}, you may want to clean up the relevant
|
||||
work directories (e.g. distsrc-*) before recodesigning
|
||||
|
||||
Hint: To blow everything away, you may want to use:
|
||||
|
||||
$ ./contrib/guix/guix-clean
|
||||
|
||||
Specifically, this will remove all files without an entry in the index,
|
||||
excluding the SDK directory, the depends download cache, the depends built
|
||||
packages cache, the garbage collector roots for Guix environments, and the
|
||||
output directory.
|
||||
EOF
|
||||
}
|
||||
|
||||
# shellcheck disable=SC2153
|
||||
for host in $HOSTS; do
|
||||
|
||||
# Display proper warning when the user interrupts the build
|
||||
trap 'int_trap ${host}' INT
|
||||
|
||||
(
|
||||
# Required for 'contrib/guix/manifest.scm' to output the right manifest
|
||||
# for the particular $HOST we're building for
|
||||
export HOST="$host"
|
||||
|
||||
# shellcheck disable=SC2030
|
||||
cat << EOF
|
||||
INFO: Codesigning ${VERSION:?not set} for platform triple ${HOST:?not set}:
|
||||
...using reference timestamp: ${SOURCE_DATE_EPOCH:?not set}
|
||||
...from worktree directory: '${PWD}'
|
||||
...bind-mounted in container to: '/feather'
|
||||
...in build directory: '$(distsrc_for_host "$HOST")'
|
||||
...bind-mounted in container to: '$(DISTSRC_BASE=/distsrc-base && distsrc_for_host "$HOST")'
|
||||
...outputting in: '$(outdir_for_host "$HOST" codesigned)'
|
||||
...bind-mounted in container to: '$(OUTDIR_BASE=/outdir-base && outdir_for_host "$HOST" codesigned)'
|
||||
...using detached signatures in: '${GUIX_SIGS_REPO:?not set}'
|
||||
...bind-mounted in container to: '/detached-sigs'
|
||||
EOF
|
||||
|
||||
# shellcheck disable=SC2086,SC2031
|
||||
time-machine shell --manifest="${PWD}/contrib/guix/manifest.scm" \
|
||||
--container \
|
||||
--pure \
|
||||
--no-cwd \
|
||||
--share="$PWD"=/feather \
|
||||
--share="$DISTSRC_BASE"=/distsrc-base \
|
||||
--share="$OUTDIR_BASE"=/outdir-base \
|
||||
--share="$LOGDIR_BASE"=/logdir-base \
|
||||
--share="$GUIX_SIGS_REPO"=/guix-sigs \
|
||||
--expose="$(git rev-parse --git-common-dir)" \
|
||||
--expose="$(git -C "$GUIX_SIGS_REPO" rev-parse --git-common-dir)" \
|
||||
${SOURCES_PATH:+--share="$SOURCES_PATH"} \
|
||||
--cores="$JOBS" \
|
||||
--keep-failed \
|
||||
--fallback \
|
||||
--link-profile \
|
||||
--user="user" \
|
||||
--root="$(profiledir_for_host "${HOST}" codesigned)" \
|
||||
${SUBSTITUTE_URLS:+--substitute-urls="$SUBSTITUTE_URLS"} \
|
||||
${ADDITIONAL_GUIX_COMMON_FLAGS} ${ADDITIONAL_GUIX_ENVIRONMENT_FLAGS} \
|
||||
-- env HOST="$host" \
|
||||
DISTNAME="$DISTNAME" \
|
||||
VERSION="$VERSION" \
|
||||
JOBS="$JOBS" \
|
||||
SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:?unable to determine value}" \
|
||||
${V:+V=1} \
|
||||
${SOURCES_PATH:+SOURCES_PATH="$SOURCES_PATH"} \
|
||||
DISTSRC="$(DISTSRC_BASE=/distsrc-base && distsrc_for_host "$HOST")" \
|
||||
OUTDIR="$(OUTDIR_BASE=/outdir-base && outdir_for_host "$HOST" codesigned)" \
|
||||
LOGDIR="$(LOGDIR_BASE=/logdir-base && logdir_for_host "$HOST" codesigned)" \
|
||||
GUIX_SIGS_REPO=/guix-sigs \
|
||||
UNSIGNED_FILE="$(OUTDIR_BASE=/outdir-base && unsigned_file_for_host "$HOST")" \
|
||||
bash -c "cd /feather && bash contrib/guix/libexec/codesign.sh"
|
||||
)
|
||||
|
||||
done
|
115
contrib/guix/libexec/codesign.sh
Executable file
115
contrib/guix/libexec/codesign.sh
Executable file
|
@ -0,0 +1,115 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2021-2022 The Bitcoin Core developers
|
||||
# Copyright (c) 2024-2024 The Monero Project
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
export LC_ALL=C
|
||||
set -e -o pipefail
|
||||
export TZ=UTC
|
||||
|
||||
# Although Guix _does_ set umask when building its own packages (in our case,
|
||||
# this is all packages in manifest.scm), it does not set it for `guix
|
||||
# shell`. It does make sense for at least `guix shell --container`
|
||||
# to set umask, so if that change gets merged upstream and we bump the
|
||||
# time-machine to a commit which includes the aforementioned change, we can
|
||||
# remove this line.
|
||||
#
|
||||
# This line should be placed before any commands which creates files.
|
||||
umask 0022
|
||||
|
||||
if [ -n "$V" ]; then
|
||||
# Print both unexpanded (-v) and expanded (-x) forms of commands as they are
|
||||
# read from this file.
|
||||
set -vx
|
||||
# Set VERBOSE for CMake-based builds
|
||||
export VERBOSE="$V"
|
||||
fi
|
||||
|
||||
# Check that required environment variables are set
|
||||
cat << EOF
|
||||
Required environment variables as seen inside the container:
|
||||
UNSIGNED_FILE: ${UNSIGNED_FILE:?not set}
|
||||
GUIX_SIGS_REPO: ${GUIX_SIGS_REPO:?not set}
|
||||
DISTNAME: ${DISTNAME:?not set}
|
||||
VERSION: ${VERSION:?not set}
|
||||
HOST: ${HOST:?not set}
|
||||
SOURCE_DATE_EPOCH: ${SOURCE_DATE_EPOCH:?not set}
|
||||
DISTSRC: ${DISTSRC:?not set}
|
||||
OUTDIR: ${OUTDIR:?not set}
|
||||
LOGDIR: ${LOGDIR:?not set}
|
||||
EOF
|
||||
|
||||
ACTUAL_OUTDIR="${OUTDIR}"
|
||||
OUTDIR="${DISTSRC}/output"
|
||||
|
||||
git_head_version() {
|
||||
local recent_tag
|
||||
if recent_tag="$(git -C "$1" describe --exact-match HEAD 2> /dev/null)"; then
|
||||
echo "${recent_tag#v}"
|
||||
else
|
||||
git -C "$1" rev-parse --short=12 HEAD
|
||||
fi
|
||||
}
|
||||
|
||||
mkdir -p "$OUTDIR"
|
||||
|
||||
mkdir -p "$DISTSRC"
|
||||
(
|
||||
cd "$DISTSRC"
|
||||
|
||||
case "$HOST" in
|
||||
*mingw32*)
|
||||
infile_base="$(basename "$UNSIGNED_FILE")"
|
||||
outfile_base="${infile_base/-unsigned}"
|
||||
|
||||
# Codesigned *-unsigned.exe and output to OUTDIR
|
||||
osslsigncode attach-signature \
|
||||
-in "$UNSIGNED_FILE" \
|
||||
-out "${OUTDIR}/$outfile_base" \
|
||||
-CAfile "$GUIX_ENVIRONMENT/etc/ssl/certs/ca-certificates.crt" \
|
||||
-sigin /guix-sigs/codesignatures/"${VERSION}"/"$outfile_base".pem
|
||||
;;
|
||||
*)
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
) # $DISTSRC
|
||||
|
||||
|
||||
(
|
||||
cd "$OUTDIR"
|
||||
|
||||
case "$HOST" in
|
||||
*mingw32.installer)
|
||||
find . -print0 \
|
||||
| xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}"
|
||||
find . \
|
||||
| sort \
|
||||
| zip -X@ "${OUTDIR}/${DISTNAME}-win-installer.zip" \
|
||||
|| ( rm -f "${OUTDIR}/${DISTNAME}-win-installer.zip" && exit 1 )
|
||||
;;
|
||||
*mingw32*)
|
||||
find . -print0 \
|
||||
| xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}"
|
||||
find . \
|
||||
| sort \
|
||||
| zip -X@ "${OUTDIR}/${DISTNAME}-win.zip" \
|
||||
|| ( rm -f "${OUTDIR}/${DISTNAME}-win.zip" && exit 1 )
|
||||
;;
|
||||
esac
|
||||
)
|
||||
|
||||
rm -rf "$ACTUAL_OUTDIR"
|
||||
mv --no-target-directory "$OUTDIR" "$ACTUAL_OUTDIR" \
|
||||
|| ( rm -rf "$ACTUAL_OUTDIR" && exit 1 )
|
||||
|
||||
(
|
||||
cd /outdir-base
|
||||
mkdir -p "$LOGDIR"/codesigned
|
||||
{
|
||||
find "$ACTUAL_OUTDIR" -type f
|
||||
} | xargs realpath --relative-base="$PWD" \
|
||||
| xargs sha256sum \
|
||||
| sort -k2 \
|
||||
| sponge "$LOGDIR"/SHA256SUMS.part
|
||||
)
|
|
@ -263,7 +263,7 @@ chain for " target " development."))
|
|||
(define osslsigncode
|
||||
(package
|
||||
(name "osslsigncode")
|
||||
(version "2.5")
|
||||
(version "2.9")
|
||||
(source (origin
|
||||
(method git-fetch)
|
||||
(uri (git-reference
|
||||
|
@ -271,9 +271,9 @@ chain for " target " development."))
|
|||
(commit version)))
|
||||
(sha256
|
||||
(base32
|
||||
"1j47vwq4caxfv0xw68kw5yh00qcpbd56d7rq6c483ma3y7s96yyz"))))
|
||||
"160dwjzpwaxism6r7ryn7dgfq78rk3nkbg9m2kwg512hhn20blqh"))))
|
||||
(build-system cmake-build-system)
|
||||
(inputs (list openssl))
|
||||
(inputs (list openssl zlib))
|
||||
(home-page "https://github.com/mtrojnar/osslsigncode")
|
||||
(synopsis "Authenticode signing and timestamping tool")
|
||||
(description "osslsigncode is a small tool that implements part of the
|
||||
|
@ -336,7 +336,7 @@ thus should be able to compile on most platforms where these exist.")
|
|||
xcb-util-wm
|
||||
)
|
||||
(let ((target (getenv "HOST")))
|
||||
(cond ((string-suffix? "-mingw32" target)
|
||||
(cond ((string-contains target "-mingw32")
|
||||
;; Windows
|
||||
(list
|
||||
gcc-toolchain-12
|
||||
|
|
Loading…
Reference in a new issue