Various fixes to sign-my-commit:

- more consistent use of quotes
 - add additional feedback when signature is already detected
 - add --force option
 - only select latest signature if multiple signature headers found

Fix squash-my-commit when signature not requested
This commit is contained in:
Simon Marsh 2025-05-04 09:13:28 +01:00
parent 90e85ae9cf
commit 21ed480098
No known key found for this signature in database
GPG key ID: E9B4156C1659C079
2 changed files with 129 additions and 94 deletions

View file

@ -34,6 +34,7 @@ Generic options:
--push, force push the result after signature and verification
--verify, check an existing signature on the latest commit
--commit <hash>, check the signature on a specific commit
--force, override some checks and continue on errors
--help, display this message
PGP specific options:
@ -47,6 +48,9 @@ SSH specific options:
--method <type>, either 'git' or 'comment' to force SSH signatures
to use a specific method, defaults to 'git'
Some parameters can also be set via environment variables,
see the defaults section in the script for more details.
EOF
}
@ -54,15 +58,16 @@ EOF
##########################################################################
# defaults
DO_PUSH=0
DO_SQUASH=1
AUTH_METHOD=''
MNTNER=''
SSH_KEYFILE=''
SSH_METHOD='git'
GPG_PRINT=''
VERIFY_ONLY=0
COMMIT_SHA=''
DO_PUSH=${DO_PUSH:-0}
DO_SQUASH=${DO_SQUASH:-1}
AUTH_METHOD=${AUTH_METHOD:-''}
MNTNER=${MNTNER:-''}
SSH_KEYFILE=${SSH_KEYFILE:-''}
SSH_METHOD=${SSH_METHOD:-'git'}
GPG_PRINT=${GPG_PRINT:-''}
VERIFY_ONLY=${VERIFY_ONLY:-0}
COMMIT_SHA=${COMMIT_SHA:-''}
FORCE=${FORCE:-0}
##########################################################################
# parse arguments
@ -103,6 +108,9 @@ do
shift
GPG_PRINT="$1"
;;
--force)
FORCE=1
;;
--help)
usage
exit 0
@ -110,7 +118,7 @@ do
*)
if [ -z "$MNTNER" ]
then
MNTNER=$1
MNTNER="$1"
else
>&2 echo "ERROR: Unknown option: $1"
>&2 usage
@ -129,7 +137,7 @@ done
# check working directory
if [ ! -d '.git' ] && [ ! -d 'data/mntner' ]
then
>&2 echo "ERROR: This script must be run in the root directory of a registry clone"
>&2 echo 'ERROR: This script must be run in the root directory of a registry clone'
exit 1
fi
@ -151,7 +159,7 @@ then
then
MNTNER=$(git log "$COMMIT_SHA" -n 1 --format=format:%B | \
grep '^### mntner:' | \
cut -d':' -f2 | tr -d ' ')
cut -d':' -f2 | tr -d ' ' | tail -n 1)
if [ -n "$MNTNER" ]
then
echo "Found mntner $MNTNER from signature"
@ -162,7 +170,7 @@ then
then
AUTH_METHOD=$(git log "$COMMIT_SHA" -n 1 --format=format:%B | \
grep '^### method:' | \
cut -d':' -f2 | tr -d ' ')
cut -d':' -f2 | tr -d ' ' | tail -n 1)
if [ -n "$AUTH_METHOD" ]
then
echo "Using $AUTH_METHOD auth method from signature"
@ -191,8 +199,8 @@ gitv_minor=$(git --version | cut -d'.' -f2)
if { [ "$gitv_major" -eq 2 ] && [ "$gitv_minor" -lt 5 ]; } || \
[ "$gitv_major" -lt 2 ]
then
>&2 echo "ERROR: This script requires a git version 2.5"
>&2 echo "---"
>&2 echo 'ERROR: This script requires a git version 2.5'
>&2 echo '---'
>&2 git --version
exit 1
fi
@ -204,9 +212,9 @@ then
# check for untracked or uncommitted changes
if [ -n "$(git status --porcelain)" ]
then
>&2 echo "ERROR: git worktree has unstaged or uncommitted changes"
>&2 echo "This script can only be run once your commit is completed"
>&2 echo "---"
>&2 echo 'ERROR: git worktree has unstaged or uncommitted changes'
>&2 echo 'This script can only be run once your commit is completed'
>&2 echo '---'
>&2 git status
exit 1
fi
@ -216,8 +224,8 @@ then
then
if ! ./squash-my-commits --verify
then
>&2 echo "ERROR: Ensure your commits are squashed before signing"
>&2 echo "Run the included script: ./squash-my-commits"
>&2 echo 'ERROR: Ensure your commits are squashed before signing'
>&2 echo 'Run the included script: ./squash-my-commits'
exit 1
fi
fi
@ -225,10 +233,21 @@ then
# check for an existing signature
if git log -n 1 --format=format:%B 2>&1 | grep '^### DN42 Signature' > /dev/null
then
>&2 echo "ERROR: The last commit appears to already be signed"
>&2 echo "---"
>&2 git log -n 1 --show-signature
exit 1
>&2 echo 'ERROR: Detected ### DN42 Signature header in commit comment'
>&2 echo 'ERROR: The commit appears to be signed already'
if [ "$FORCE" -ne 0 ]
then
>&2 echo '!!! ignoring errors, continuing'
else
>&2 echo '---'
>&2 git log -n 1 --show-signature
>&2 echo '---'
>&2 echo 'If you want to re-try signing the commit then you must either'
>&2 echo 're-run this script again using the --force option, or'
>&2 echo 'manually remove the "### DN42 Signature" header from the commit'
>&2 echo 'comment (e.g. using git commit --amend)'
exit 1
fi
fi
fi
@ -316,10 +335,18 @@ sign_pgp()
# check first if there is already a signature
if git log -n 1 --show-signature | grep "^gpg" > /dev/null 2>&1
then
>&2 echo "ERROR: The last commit appears to already be signed."
>&2 echo "---"
>&2 git log -n 1 --show-signature
exit 1
>&2 echo 'ERROR: Found existing git signature'
>&2 echo 'ERROR: The last commit appears to be signed already'
if [ "$FORCE" -ne 0 ]
then
>&2 echo '!!! ignoring errors, continuing'
else
>&2 echo "---"
>&2 git log -n 1 --show-signature
>&2 echo "---"
>&2 echo "You can use the --force option for re-try signing"
exit 1
fi
fi
# if the fingerprint wasn't specified, obtain from the MNTNER
@ -360,15 +387,15 @@ sign_pgp()
verify_pgp()
{
echo "Verifying PGP signature"
echo 'Verifying PGP signature'
# requires git 2.5
if ! git verify-commit "$COMMIT_SHA"
then
>&2 echo "ERROR: failed to verify PGP signature"
>&2 echo 'ERROR: failed to verify PGP signature'
exit 1
fi
echo " - PGP signature verified ok"
echo ' - PGP signature verified ok'
# create a list of authorised pgp fingerprints
valid_prints=$(get_pgp_prints)
@ -381,7 +408,7 @@ verify_pgp()
if grep "$print" "$valid_prints" > /dev/null 2>&1
then
echo "Matched fingerprint with auth attribute for $MNTNER"
echo "Successfully verified PGP signature"
echo 'Successfully verified PGP signature'
rm "$valid_prints"
return
fi
@ -438,8 +465,8 @@ check_keyfile()
filter_ssh_auths | head -n 1 > "$pubkeyfile"
if [ ! -s "$pubkeyfile" ]
then
>&2 echo "ERROR: Unable to auto determine SSH public key"
>&2 echo "Try specifying the key directly using --key"
>&2 echo 'ERROR: Unable to auto determine SSH public key'
>&2 echo 'Try specifying the key directly using --key'
rm "$pubkeyfile"
exit 1
fi
@ -487,8 +514,8 @@ EOF
if ! pubkey=$(ssh-keygen -l -f "$SSH_KEYFILE")
then
>&2 echo "ERROR: $SSH_KEYFILE doesn't look like a valid SSH key"
>&2 echo "Try specifying the public or private key directly using --key"
>&2 echo "File contents:"
>&2 echo 'Try specifying the public or private key directly using --key'
>&2 echo 'File contents:'
>&2 cat "$SSH_KEYFILE"
if [ -n "$pubkeyfile" ]; then rm "$pubkeyfile"; fi
exit 1
@ -527,9 +554,9 @@ sign_ssh_git()
# was there an error ?
if [ "$result" -ne 0 ]
then
>&2 echo "ERROR: failed to sign commit"
>&2 echo " - Try specifying your key using --key"
>&2 echo " - or adding your key to ssh-agent"
>&2 echo 'ERROR: failed to sign commit'
>&2 echo ' - Try specifying your key using --key'
>&2 echo ' - or adding your key to ssh-agent'
exit 1
fi
@ -554,9 +581,9 @@ sign_ssh_comment()
# check for errors
if [ "$result" -ne 0 ]
then
>&2 echo "ERROR: ssh-keygen signing failed"
>&2 echo " - Try specifying your key using --key"
>&2 echo " - or adding the key to ssh-agent"
>&2 echo 'ERROR: ssh-keygen signing failed'
>&2 echo ' - Try specifying your key using --key'
>&2 echo ' - or adding the key to ssh-agent'
if [ -n "$pubkeyfile" ]; then rm "$pubkeyfile"; fi
exit 1
fi
@ -599,20 +626,20 @@ EOF
fi
# if we have git >= 2.34 the commit can be git signed
if [ "$SSH_METHOD" != "comment" ]
if [ "$SSH_METHOD" != 'comment' ]
then
if { [ "$gitv_major" -eq 2 ] && [ "$gitv_minor" -ge 34 ]; } || \
[ "$gitv_major" -gt 2 ]
then
echo "Detected git version >= 2.34, using git SSH signature"
echo 'Detected git version >= 2.34, using git SSH signature'
sign_ssh_git
return
else
echo "Detected git version < 2.34, cannot sign using git"
echo 'Detected git version < 2.34, cannot sign using git'
fi
fi
echo "Defaulting to comment based signature"
echo 'Defaulting to comment based signature'
sign_ssh_comment
}
@ -628,8 +655,8 @@ verify_ssh_git()
if { [ "$gitv_major" -eq 2 ] && [ "$gitv_minor" -lt 34 ]; } || \
[ "$gitv_major" -lt 2 ]
then
>&2 echo "Detected git version < 2.34, unable to verify git signatures"
>&2 echo "- Upgrade git to at least version 2.34"
>&2 echo 'Detected git version < 2.34, unable to verify git signatures'
>&2 echo '- Upgrade git to at least version 2.34'
exit 1
fi
@ -650,17 +677,17 @@ verify_ssh_git()
# did the signature successfully validate ?
if [ "$result" -ne 0 ]
then
>&2 echo "ERROR: failed to verify SSH signature"
>&2 echo 'ERROR: failed to verify SSH signature'
exit 1
fi
echo "SSH signature verified ok"
echo 'SSH signature verified ok'
}
# verify a comment based SSH signature
verify_ssh_comment()
{
echo "Verifying SSH signature comment"
echo 'Verifying SSH signature comment'
# create the allowed signers file
allowed=$(get_allowed_signers)
@ -671,8 +698,8 @@ verify_ssh_comment()
# also extract the SSH signature from the comment
signature=$(mktemp)
begin="-----BEGIN SSH SIGNATURE-----"
end="-----END SSH SIGNATURE-----"
begin='-----BEGIN SSH SIGNATURE-----'
end='-----END SSH SIGNATURE-----'
git log "$COMMIT_SHA" -n 1 --format=format:%B | \
sed "/^$begin\$/,/^$end\$/!d" > "$signature"
@ -686,9 +713,9 @@ verify_ssh_comment()
# did it work ?
if [ "$result" -eq 0 ]
then
echo "Successfully verified SSH sigature"
echo 'Successfully verified SSH sigature'
else
>&2 echo "ERROR: signature verification failed"
>&2 echo 'ERROR: signature verification failed'
exit 1
fi
}
@ -698,7 +725,7 @@ verify_ssh()
{
# determine signature type from log comment
method=$(git log "$COMMIT_SHA" -n 1 --format=format:%B | \
grep '^### method:' | cut -d':' -f2 | tr -d ' ')
grep '^### method:' | cut -d':' -f2 | tr -d ' ' | tail -n 1)
case "$method" in
'ssh')
verify_ssh_comment
@ -707,11 +734,11 @@ verify_ssh()
verify_ssh_git
;;
'')
echo "WARNING: No dn42 signature found, attempting git based verification"
echo 'WARNING: No dn42 signature found, attempting git based verification'
verify_ssh_git
;;
*)
>&2 echo "ERROR: commit does not appear to be signed by SSH"
>&2 echo 'ERROR: commit does not appear to be signed by SSH'
>&2 echo "Found signature method: $method"
exit 1
;;
@ -728,7 +755,7 @@ if [ -z "$AUTH_METHOD" ]
then
if [ "$VERIFY_ONLY" -ne 1 ]
then
echo "Attempting to guess signature method from mntner object"
echo 'Attempting to guess signature method from mntner object'
AUTH_METHOD=$(guess_mntner_method)
fi
fi
@ -738,27 +765,29 @@ case "$AUTH_METHOD" in
pgp)
if [ "$VERIFY_ONLY" -ne 1 ]
then
echo "Signing using PGP key"
echo 'Signing using PGP key'
sign_pgp
fi
echo '---'
verify_pgp
;;
ssh|ssh-git)
if [ "$VERIFY_ONLY" -ne 1 ]
then
echo "Signing using SSH key"
echo 'Signing using SSH key'
sign_ssh
fi
echo '---'
verify_ssh
;;
'')
>&2 echo "ERROR: Unable to automatically determine signing method"
>&2 echo "Use the --ssh or --pgp options to force a particular method"
>&2 echo 'ERROR: Unable to automatically determine signing method'
>&2 echo 'Use the --ssh or --pgp options to force a particular method'
exit 1
;;
*)
>&2 echo "ERROR: Unknown or unimplemented auth method: $AUTH_METHOD"
>&2 echo "Use the --ssh or --pgp options to force a particular method"
>&2 echo 'Use the --ssh or --pgp options to force a particular method'
exit 1
;;
esac

View file

@ -30,13 +30,14 @@ usage()
do_push=0
verify_only=0
do_sign=0
for arg
do
case "$arg" in
-S)
do_sign='-S'
do_sign=1
;;
--push)
do_push=1
@ -156,7 +157,12 @@ $(git log --oneline HEAD ^dn42registry/master)"
# and finally squash
git reset --soft dn42registry/master
git commit "$do_sign" -m "$comment"
if [ "$do_sign" -eq 1 ]
then
git commit -S -m "$comment"
else
git commit -m "$comment"
fi
# show what happened
echo '---'