#!/bin/bash # gentoo-infra: infra/githooks.git:update-02-gpg # --- Command line refname=${1} oldrev=${2} newrev=${3} # --- Safety check if [ -z "${GIT_DIR}" ]; then echo "Don't run this script from the command line." >&2 echo " (if you want, you could supply GIT_DIR then run" >&2 echo " ${0} )" >&2 exit 1 fi if [ -z "${refname}" -o -z "${oldrev}" -o -z "${newrev}" ]; then echo "usage: ${0} " >&2 exit 1 fi # branch names or 'all', or 'all-refs' for all refs SIGNED_BRANCHES=$(git config --get gentoo.signed-branches) : ${SIGNED_BRANCHES:=master} VERIFY_SIGS=$(git config --get gentoo.verify-signatures) : ${VERIFY_SIGS:=gentoo-devs} case ${VERIFY_SIGS} in gentoo-devs) if [[ ${GL_USER} != *@gentoo.org ]]; then echo "*** Pusher address is not @gentoo.org" >&2 echo " (it is ${GL_USER})" >&2 echo "*** Please report this to infra ($0)" >&2 exit 1 fi # find key fingerprints in LDAP KEY_FPS=$(ldapsearch "uid=${GL_USER%@gentoo.org}" -D '' -Z -LLL \ gpgfingerprint -o ldif-wrap=no | \ sed -n -e '/^gpgfingerprint: /{s/^.*://;s/ //g;p}') # verify GLEP63 compliance GOOD_KEYS=() HAVE_NONCOMPLIANT=no for K in ${KEY_FPS}; do LC_CTYPE=en_US.UTF-8 \ glep63-check -S glep63-2 -k "${K}" && GOOD_KEYS+=( "${K}" ) || HAVE_NONCOMPLIANT=yes done if [[ ${#GOOD_KEYS[@]} -eq 0 ]]; then echo "*** None of your keys comply with GLEP 63." >&2 echo " Please update the keys into conformance if you wish to continue" >&2 echo " using them. If not, please remove unused keys from LDAP." >&2 exit 1 elif [[ ${HAVE_NONCOMPLIANT} == yes ]]; then echo "*** Warning. One or more OpenPGP keys do not comply with GLEP 63." >&2 echo " Please update the keys into conformance if you wish to continue" >&2 echo " using them. If not, please remove unused keys from LDAP." >&2 fi # create a dedicated GNUPGHOME TMPHOME=$(mktemp -d) trap 'rm -rf "${TMPHOME}"' EXIT # transfer the keys: # - ONLY for the developer/service in question # - with chain to L1 CHAIN_L1=( ABD00913019D6354BA1D9A132839FE0D796198B1 # openpgp-auth+l1@gentoo.org ) CHAIN_L2=( 2C13823B8237310FA213034930D132FF0FF50EEB # openpgp-auth+l2-dev@gentoo.org 18F703D702B1B9591373148C55D3238EC050396E # openpgp-auth+l2-srv@gentoo.org ) EXPORT_CMD=( gpg -q --export-options export-clean,no-export-local-sigs,no-export-attributes # keep-uid filter is not working in gnupg-2.4.3 or gnupg-2.2.41 #--export-filter 'keep-uid="uid =~ @gentoo.org"' --export ) IMPORT_CMD=( gpg -q # no-self-sigs-only is needed to import the signature chain. --import-options import-clean,no-import-local-sigs,no-keep-ownertrust,no-self-sigs-only # keep-uid filter is not working in gnupg-2.4.3 or gnupg-2.2.41 #--import-filter 'keep-uid="uid =~ @gentoo.org"' --import ) "${EXPORT_CMD[@]}" \ "${CHAIN_L1[@]}" \ "${CHAIN_L2[@]}" \ "${GOOD_KEYS[@]}" \ | \ GNUPGHOME=${TMPHOME} \ "${IMPORT_CMD[@]}" # use new GNUGPHOME to restrict to dev's keys export GNUPGHOME=${TMPHOME} cat >>$GNUPGHOME/gpg.conf <<-EOF # Explicitly set trust model; # git-2.43 does not recognize the always & direct trust model behavior # so it exports that the signatures came from an untrusted key trust-model pgp EOF # And declare that the L1 key is trusted. # This could go into the trustdb file instead, but cleaner this way. for _k in "${CHAIN_L1[@]}" ; do echo "trusted-key $_k" >> $GNUPGHOME/gpg.conf done # If there are problems w/ the key export/import loop, or trust # verification; dump here #GNUPGHOME=${TMPHOME} gpg --check-trustdb #GNUPGHOME=${TMPHOME} gpg --list-sig ;; no) ;; *) echo "Invalid value of gentoo.verify-signatures" >&2 exit 1 esac case ${SIGNED_BRANCHES} in all-refs) ;; all) [[ ${refname} == refs/heads/* ]] || exit 0 ;; *) [[ ${refname} == refs/heads/* ]] || exit 0 branch_found= for branch in ${SIGNED_BRANCHES}; do if [[ ${refname#refs/heads/} == ${branch} ]]; then branch_found=1 break fi done [[ ${branch_found} == 1 ]] || exit 0 esac IFS=' ' # special cases zeros=0000000000000000000000000000000000000000 # branch removal [[ ${newrev} == "${zeros}" ]] && exit 0 # new branch; try to find a merge base with master if [[ ${oldrev} == "${zeros}" && ${refname} != refs/heads/master ]]; then mergebase=$(git merge-base refs/heads/master "${newrev}") [[ -n ${mergebase} ]] && oldrev=${mergebase} fi rev_list_arg="${oldrev}..${newrev}" # new and no common commit? gotta check them all [[ ${oldrev} == "${zeros}" ]] && rev_list_arg="${newrev}" while read -r r; do committer=$(git show -q --pretty=format:'%ce' "${r}") if [[ ${VERIFY_SIGS} == gentoo-devs && ${committer} != *@gentoo.org ]]; then echo "*** Committer address is not @gentoo.org, refusing" exit 1 fi signst=$(git show -q --pretty=format:'%G?' "${r}") case ${VERIFY_SIGS} in gentoo-devs) # gentoo dev signatures must be Good [[ ${signst} == G ]] && continue ;; no) # additionally skip untrusted/impossible to check # when verification is disabled [[ ${signst} == [GUE] ]] && continue ;; esac # error reporting case ${signst} in U) echo "*** Untrusted signature on ${r}, refusing" exit 1 ;; B) echo "*** Bad signature on ${r}, refusing" exit 1 ;; N) echo "*** No signature on ${r}, refusing" exit 1 ;; E) echo "*** Signature cannot be checked on ${r}, refusing" exit 1 ;; *) echo "*** Unknown signature status '${signst}', refusing" exit 1 ;; esac done < <(git rev-list --first-parent "${rev_list_arg}") # --- Finished exit 0