Multiple fixes to 015cosmos-trust

* Before this the tool would not try to re-import a key file unless the
  key was expired, but if that key was also the one that signed the
  ops-repo this would never happen as the key would expire and
  update.d/25verify-git would prevent this script from running.
  Now we always import files if the contained key is not expired so we
  will read in updated files before they expire.

* Only import a key file if it includes a single pubkey. Before this
  the code seems to have accepted files with multiple keys yet the
  fingerprint parsing only found the first fingerprint so it would clean
  up additional keys on follow-up runs as it considered the additional
  fingerprints missing.

* Fix SEEN check that aborted the tool if no keys at all have been seen.
  The previous check probably never worked.

* Fix code that checked Ubuntu version to specifically check for Ubuntu
  otherwise the tool uses unexpected flags on Debian as they use lower
  version numbers than Ubuntu.

* Various tweaks to silence shellcheck.
This commit is contained in:
Patrik Lundin 2025-05-19 15:54:03 +02:00
parent 3869975ed4
commit 6919fc7849
Signed by: patlu
GPG key ID: A0A812BA2249F294

View file

@ -1,10 +1,10 @@
#!/bin/bash
gnupg_show_options='--import --import-options show-only,import-minimal'
if [[ $(lsb_release -sr | awk -F . '{ print $1 }') -le 16 ]]; then
gnupg_show_options=("--import" "--import-options" "show-only,import-minimal")
if [[ $(lsb_release -si) = "Ubuntu" ]] && [[ $(lsb_release -sr | awk -F . '{ print $1 }') -le 16 ]]; then
# gpg on Ubuntu 16 and less is gnupg < 2, which doesn't have --import-options show-only
# but on the other hand defaults to this mode (https://dev.gnupg.org/T2943)
gnupg_show_options='--dry-run'
gnupg_show_options=("--dry-run")
fi
if [ -z "$COSMOS_KEYS" ]; then
@ -18,61 +18,59 @@ red='\033[01;31m'
# Associative array of fingerprints in the GPG keyring
declare -A KEYRING
# Associative array with expired keys in the GPG keyring
declare -A EXPIRED
# associative array with non-expired keys found in $COSMOS_KEYS directory
declare -A SEEN
# Load information about all keys present in the GPG keyring
for line in $(cosmos gpg --with-colons --fingerprint | awk -F: '$1 == "pub" { print $2 ":" $5 }'); do
IFS=':' read -r expired fp <<< $line
KEYRING[$fp]='1'
if [[ $expired == 'e' ]]; then
EXPIRED[$fp]=1
fi
done
# Install new keys discovered in the $COSMOS_KEYS directory
for k in $COSMOS_KEYS/*.pub; do
# Make sure we have a fresh view of all previously accepted keys
for k in "$COSMOS_KEYS"/*.pub; do
if [[ ! -s $k ]]; then
# Silently ignore empty files
continue
fi
pubkeys_in_file=$(cosmos gpg ${gnupg_show_options} \
--with-colons --with-fingerprint --quiet < $k \
pubkeys_in_file=$(cosmos gpg "${gnupg_show_options[@]}" \
--with-colons --with-fingerprint --quiet < "$k" \
| grep "^pub:")
non_expired_pubkeys_in_file=$(echo ${pubkeys_in_file} | awk -F: '$2 != "e" { print $0 }')
if [[ ! $non_expired_pubkeys_in_file ]]; then
# We only support files with one key in them
num_pub_keys=$(echo "$pubkeys_in_file" | wc -l)
if [ "$num_pub_keys" -ne 1 ]; then
echo -e "$0: ${red}Ignoring file that does not have exactly one pubkey (found $num_pub_keys): ${k}${reset}"
continue
fi
expired_pubkey_in_file=$(echo "${pubkeys_in_file}" | awk -F: '$2 == "e" { print $0 }')
if [[ $expired_pubkey_in_file ]]; then
echo -e "$0: ${red}Ignoring file with expired pubkey: ${k}${reset}"
continue
fi
fp=$(echo ${pubkeys_in_file} | awk -F: '{print $5}')
fp=$(echo "${pubkeys_in_file}" | awk -F: '{print $5}')
# Remember that we saw fingerprint $fp in file $k
SEEN[$fp]=$k
if [[ ! ${KEYRING[$fp]} ]]; then
echo -e "$0: ${bold}Importing new key ${fp}${reset} from ${k}"
cosmos gpg --no-tty --import < $k
elif [[ ${EXPIRED[$fp]} ]]; then
echo -e "$0: ${bold}Re-importing expired key ${fp}${reset} from ${k}"
cosmos gpg --no-tty --import < $k
fi
# Always import a non-expired file since it may have been updated
gpg_output=$(cosmos gpg --no-tty --import < "$k" 2>&1)
# Only print output if a key is changed
echo "$gpg_output" | grep -q " not changed$" || echo "$gpg_output"
done
if [[ ! ${#SEEN[@]} ]]; then
echo "$0: ${red}NO trusted keys found in directory ${COSMOS_KEYS} - aborting${reset}"
# Load information about all keys present in the GPG keyring
for fp in $(cosmos gpg --with-colons --fingerprint | awk -F: '$1 == "pub" { print $5 }'); do
KEYRING[$fp]='1'
done
if (( ${#SEEN[@]} == 0 )); then
echo -e "$0: ${red}NO trusted keys found in directory ${COSMOS_KEYS} - aborting${reset}"
echo "(this is probably a syntax problem with the gpg commands in this script)"
exit 1
fi
# Delete keys no longer present (or expired) in $COSMOS_KEYS directory
for fp in ${!KEYRING[@]}; do
for fp in "${!KEYRING[@]}"; do
if [[ ! ${SEEN[$fp]} ]]; then
echo -e "$0: ${bold}Deleting key${reset} ${fp} not present (or expired) in ${COSMOS_KEYS}"
cosmos gpg --fingerprint $fp
cosmos gpg --yes --batch --delete-key $fp || true
cosmos gpg --fingerprint "$fp"
cosmos gpg --yes --batch --delete-key "$fp" || true
fi
done