#!/bin/bash # This is a small wrapper script for gpg intended to be used by git # As far as I can tell, git cannot automatically pick a fallback signing key by itself # Setting GIT_SIGN_FALLBACK_KEY_IDS="config" or leaving it unset will make the program try all keys listed by git config # Setting GIT_SIGN_FALLBACK_KEY_IDS="all" will make the program try all keys listed by gpg # Setting the fallback keys manually can be done like this: GIT_SIGN_FALLBACK_KEY_IDS=" " # This script was written in about two hours, if you find any bugs, tell Luca! set -eu # A quick and dirty array filtering function function reject { predicate=$1 shift for el in "$@"; do if ! eval ":() { [[ $predicate ]]; }; : '$el'"; then echo "$el" fi done } case "$*" in # Git is trying to sign a commit *-bsau*) # The key passed by git primary_key=$(echo "$*" | grep -oP '(?<=-bsau )[A-Z0-9]{16}') # Select fallback keys based on config case "${GIT_SIGN_FALLBACK_KEY_IDS:-}" in "" | "config") mapfile -t signing_keys < <(git config --get-all user.signingKey) mapfile -t fallback_keys < <(reject "\$1 == $primary_key" "${signing_keys[@]}") ;; "all") mapfile -t signing_keys < <(gpg --list-keys --with-colons | awk -F: '/^pub:/ {print $5}') mapfile -t fallback_keys < <(reject "\$1 == $primary_key" "${signing_keys[@]}") ;; *) mapfile -t fallback_keys < <(echo "$GIT_SIGN_FALLBACK_KEY_IDS" | xargs -n 1) ;; esac # Number of signing keys n_keys=$(($(echo "${fallback_keys[*]}" | wc -w) + 1)) # Unaccounted for gpg flags mapfile -t extra_flags < <(reject "\$1 == -bsau || \$1 == --status-fd=2 || \$1 == $primary_key" "$@") gpg_flags=("${extra_flags[@]}" --status-fd=2 -bsau) # Try signing with the primary key first, then try the fallback keys counter=0 try_key=$primary_key while [ "$counter" -lt "$n_keys" ] && ! gpg "${gpg_flags[@]}" "$try_key" do try_key="${fallback_keys[$counter - 1]}" counter=$((counter + 1)) done ;; # Git is trying to do something else, so we just pass the flags through *) gpg "$@" ;; esac