blob: 6b3d840e24099d663cb44a125ce46f375923f8c2 [file] [log] [blame]
#!/bin/bash
#
# git-archive-signer
# ------------------
# Use this script to create a tarball signature for a tag and store
# it as part of the repo (using git notes, as supported by cgit).
# Don't change this if you want this to actually work
NOTEREF="refs/notes/signatures/tar"
NOTEREF_MINISIG="refs/notes/minisig/tar"
# Pass the tag as the only parameter, otherwise we grab the latest
# annotated tag we find. You may also pass "list" to list all tags that
# already carry corresponding signature notes.
if [[ $1 == "list" ]]; then
git notes --ref ${NOTEREF} list | cut -d' ' -f2 | xargs git describe
exit 0
fi
TAG=$1
# Set this to your gitolite.kernel.org remote
# We'll also use git config --get archive-signer.remote if we find it
REMOTE="$(git config --get archive-signer.remote)"
if [[ -z ${REMOTE} ]]; then
REMOTE="origin"
fi
# Change this if your gpg2 is elsewhere
GPGBIN="/usr/bin/gpg2"
# Change this if your minisign is elsewhere
MINISIGNBIN="/usr/bin/minisign"
# If you want to use a specific key (or subkey) instead of the default,
# then edit and uncomment this line. If you have multiple valid signing
# subkeys, then add the exact subkey ID and add a "!" at the end.
# We'll also use git config archive-signer.usekey value if we find it
#USEKEY="Ox12345678DEADBEEF"
USEKEY="$(git config --get archive-signer.usekey)"
# We use TARNAME when making a git archive --prefix, e.g. $TARNAME-1.2.3/
# Set it here if guessing basename is wrong.
# We'll also use git config archive-signer.tarname value if we find it
TARNAME="$(git config --get archive-signer.tarname)"
if [[ -z ${TARNAME} ]]; then
TARNAME="$(basename $(pwd))"
fi
# You shouldn't need to change anything below
if [[ -z ${TAG} ]]; then
# Assume you want the latest tag
TAG="$(git describe --abbrev=0)"
if [[ -z ${TAG} ]]; then
echo "Could not figure out which tag you want"
exit 1
fi
fi
# The archive prefix will be created as $TARNAME-$TAG/ (sans leading v)
# Change it here if it doesn't correspond to your needs
# We'll add the trailing / where it is needed, so don't add it here
PREFIX="${TARNAME}-${TAG#v}"
# Do we already have a signature note for this tag?
# Start by fetching the origin notes
echo "Updating notes from remote"
git fetch ${REMOTE} "refs/notes/*:refs/notes/*"
if git notes --ref=${NOTEREF} list ${TAG} >/dev/null 2>&1; then
echo "Signature note for ${TAG} already exists!"
echo "To make a new one, delete it first:"
echo " git notes --ref=${NOTEREF} remove ${TAG}"
exit 1
fi
echo -n "Generate signature note for ${PREFIX}.tar? [Y/n] "
read YN
[[ -z ${YN} ]] && YN=y
[[ ${YN} != "y" ]] && exit 1
# We add the exact archive line to sig comments,
# so put it together here
GIT_ARCHIVE_CMD="git archive --format tar --prefix=${PREFIX}/ ${TAG}"
# Record the version of git that created this archive
GIT_VERSION=$(git --version)
if [[ ! -z ${USEKEY} ]]; then
GPGBIN="${GPGBIN} -u ${USEKEY}"
fi
# We put the tarball into a temp file, in case we need to minisign it, too
TMP_ARCHIVE=$(mktemp)
echo -n "Running ${GIT_ARCHIVE_CMD}..."
${GIT_ARCHIVE_CMD} > ${TMP_ARCHIVE}
echo "done"
git notes --ref=${NOTEREF} add -C "$(
cat ${TMP_ARCHIVE} | ${GPGBIN} -a -b -o - \
--comment "This signature is for the .tar version of the archive" \
--comment "${GIT_ARCHIVE_CMD}" \
--comment "${GIT_VERSION}" |
git hash-object -w --stdin)" "${TAG}"
if [[ $? != 0 ]]; then
echo "git notes exited with error"
rm -f ${TMP_ARCHIVE}
exit 1
fi
echo
git --no-pager notes --ref=${NOTEREF} show ${TAG}
echo
USE_MINISIGN="$(git config --get archive-signer.use-minisign)"
if [[ ${USE_MINISIGN} == "yes" ]]; then
if git notes --ref=${NOTEREF_MINISIG} list ${TAG} >/dev/null 2>&1; then
echo "Minisign note for ${TAG} already exists!"
echo "To make a new one, delete it first:"
echo " git notes --ref=${NOTEREF_MINISIG} remove ${TAG}"
exit 1
fi
MINISIGN_CMD="${MINISIGNBIN}"
MINISIGN_COMMENT="This minisign signature is for the .tar version of the archive"
MINISIGN_TRUSTED="$(date -u), ${GIT_VERSION}, using: ${GIT_ARCHIVE_CMD}"
# If minisign-keyfile is set, we'll use that key instead of the default
MINISIGN_KEY="$(git config --get archive-signer.minisign-key)"
if [[ ! -z ${MINISIGN_KEY} ]]; then
MINISIGN_CMD="${MINISIGN_CMD} -s $(eval echo ${MINISIGN_KEY})"
fi
# If you don't want to type in the minisign passphrase, you can
# store it gpg-encrypted and set archive.signer.minisign-gpg-passphrase to
# point at the file containing the encrypted passphrase.
# To generate, use:
# echo passphrase | gpg -r YOURKEYID -e > minisign-passphrase.gpg
MINISIGN_PASSPHRASE="$(git config --get archive-signer.minisign-gpg-passphrase)"
MINISIGN_OUT=$(mktemp)
echo "Generating minisign signature"
if [[ -z ${MINISIGN_PASSPHRASE} ]]; then
${MINISIGN_CMD} -S \
-c "${MINISIGN_COMMENT}" -t "${MINISIGN_TRUSTED}" \
-x ${MINISIGN_OUT} -m ${TMP_ARCHIVE}
else
echo "Using the gpg-encrypted passphrase from ${MINISIGN_PASSPHRASE}"
${GPGBIN} -q -d $(eval echo ${MINISIGN_PASSPHRASE}) \
| ${MINISIGN_CMD} -S \
-c "${MINISIGN_COMMENT}" -t "${MINISIGN_TRUSTED}" \
-x ${MINISIGN_OUT} -m ${TMP_ARCHIVE}
fi
if [[ ! -s ${MINISIGN_OUT} ]]; then
# Assume minisign process went wrong
echo "Minisign signature is missing, aborting!"
rm -f ${TMP_ARCHIVE}
exit 1
fi
git notes --ref=${NOTEREF_MINISIG} add \
-C "$(cat ${MINISIGN_OUT} | git hash-object -w --stdin)" "${TAG}"
if [[ $? != 0 ]]; then
echo "git notes exited with error"
rm -f ${TMP_ARCHIVE} ${MINISIGN_OUT}
exit 1
fi
echo "-----"
git --no-pager notes --ref=${NOTEREF_MINISIG} show ${TAG}
echo "-----"
echo
rm -f ${MINISIGN_OUT}
fi
rm -f ${TMP_ARCHIVE}
echo -n "Push to ${REMOTE}? [Y/n] "
read YN
echo
[[ -z ${YN} ]] && YN=y
if [[ ${YN} != "y" ]]; then
echo "Remember to push it using:"
echo " git push ${REMOTE} refs/notes/*"
exit 0
fi
echo "Pushing notes to ${REMOTE}..."
git push ${REMOTE} refs/notes/*