#!/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/*