]> Nutra Git (v2) - gamesguru/feather.git/commitdiff
build: windows codesigning
authortobtoht <tob@featherwallet.org>
Mon, 4 Nov 2024 16:29:03 +0000 (17:29 +0100)
committertobtoht <tob@featherwallet.org>
Mon, 4 Nov 2024 16:29:03 +0000 (17:29 +0100)
contrib/guix/guix-attest
contrib/guix/guix-codesign [new file with mode: 0755]
contrib/guix/libexec/codesign.sh [new file with mode: 0755]
contrib/guix/manifest.scm

index 1f07a20510b1c5f1f5138f9031d27c8b69472626..e9a0b817a54ddbd1d4bac10f117583b501812ab7 100755 (executable)
@@ -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
diff --git a/contrib/guix/guix-codesign b/contrib/guix/guix-codesign
new file mode 100755 (executable)
index 0000000..ad08df0
--- /dev/null
@@ -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
diff --git a/contrib/guix/libexec/codesign.sh b/contrib/guix/libexec/codesign.sh
new file mode 100755 (executable)
index 0000000..33fd9b7
--- /dev/null
@@ -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
+)
index 403591cf2631353ca193ed175932ebce90dcecdf..50100f8960f908995726f36cbcd24c515ef76360 100644 (file)
@@ -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