github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/script/keyring_validate.sh (about) 1 #!/bin/bash 2 # Copyright (C) 2023 SUSE LLC. 3 # Copyright (C) 2023 Open Containers Authors 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 set -Eeuo pipefail 18 19 project="runc" 20 root="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/..")" 21 22 function log() { 23 echo "[*]" "$@" >&2 24 } 25 26 function bail() { 27 log "$@" 28 exit 1 29 } 30 31 # Temporary GPG keyring for messing around with. 32 tmp_gpgdir="$(mktemp -d --tmpdir "$project-validate-tmpkeyring.XXXXXX")" 33 trap 'rm -r "$tmp_gpgdir"' EXIT 34 35 # Get the set of MAINTAINERS. 36 readarray -t maintainers < <(sed -E 's|.* <.*> \(@?(.*)\)$|\1|' <"$root/MAINTAINERS") 37 echo "------------------------------------------------------------" 38 echo "$project maintainers:" 39 printf " * %s\n" "${maintainers[@]}" 40 echo "------------------------------------------------------------" 41 42 # Create a dummy gpg keyring from the set of MAINTAINERS. 43 while IFS="" read -r username || [ -n "$username" ]; do 44 curl -sSL "https://github.com/$username.gpg" | 45 gpg --no-default-keyring --keyring="$tmp_gpgdir/$username.keyring" --import 46 done < <(printf '%s\n' "${maintainers[@]}") 47 48 # Make sure all of the keys in the keyring have a github=... comment. 49 awk <"$root/$project.keyring" ' 50 /^-----BEGIN PGP PUBLIC KEY BLOCK-----$/ { key_idx++; in_pgp=1; has_comment=0; } 51 52 # PGP comments are never broken up over several lines, and we only have one 53 # comment entry in our keyring file anyway. 54 in_pgp && /^Comment:.* github=\w+.*/ { has_comment=1 } 55 56 /^-----END PGP PUBLIC KEY BLOCK-----$/ { 57 if (!has_comment) { 58 print "[!] Key", key_idx, "in '$project'.keyring is missing a github= comment." 59 exit 1 60 } 61 } 62 ' 63 64 echo "------------------------------------------------------------" 65 echo "$project release managers:" 66 sed -En "s|^Comment:.* github=(\w+).*| * \1|p" <"$root/$project.keyring" | sort -u 67 echo "------------------------------------------------------------" 68 gpg --no-default-keyring --keyring="$tmp_gpgdir/keyring" \ 69 --import --import-options=show-only <"$root/$project.keyring" 70 echo "------------------------------------------------------------" 71 72 # Check that each entry in the kering is actually a maintainer's key. 73 while IFS="" read -d $'\0' -r block || [ -n "$block" ]; do 74 username="$(sed -En "s|^Comment:.* github=(\w+).*|\1|p" <<<"$block")" 75 76 # FIXME: This is to work around codespell thinking that f-p-r is a 77 # misspelling of some other word, and the lack of support for inline 78 # ignores in codespell. 79 fprfield="f""p""r" 80 81 # Check the username is actually a maintainer. This is just a sanity check, 82 # since you can put whatever you like in the Comment field. 83 [ -f "$tmp_gpgdir/$username.keyring" ] || bail "User $username in runc.keyring is not a maintainer!" 84 grep "(@$username)$" "$root/MAINTAINERS" >/dev/null || bail "User $username in runc.keyring is not a maintainer!" 85 86 # Check that the key in the block actually matches a known key for that 87 # maintainer. Note that a block can contain multiple keys, so we need to 88 # check all of them. Since we have to handle multiple keys anyway, we'll 89 # also verify all of the subkeys (this is simpler to implement anyway since 90 # the --with-colons format outputs fingerprints for both primary and 91 # subkeys in the same way). 92 # 93 # Fingerprints have a field 1 of $fprfield and field 10 containing the 94 # fingerprint. See <https://github.com/gpg/gnupg/blob/master/doc/DETAILS> 95 # for more details. 96 while IFS="" read -r key || [ -n "$key" ]; do 97 gpg --no-default-keyring --keyring="$tmp_gpgdir/$username.keyring" \ 98 --list-keys --with-colons | grep "$fprfield:::::::::$key:" >/dev/null || 99 bail "(Sub?)Key $key in $project.keyring is NOT actually one of $username's keys!" 100 log "Successfully verified $username's (sub?)key $key is legitimate." 101 done < <(gpg --no-default-keyring \ 102 --import --import-options=show-only --with-colons <<<"$block" | 103 grep "^$fprfield:" | cut -d: -f10) 104 done < <(awk <"$root/$project.keyring" ' 105 /^-----BEGIN PGP PUBLIC KEY BLOCK-----$/ { in_block=1 } 106 in_block { print } 107 /^-----END PGP PUBLIC KEY BLOCK-----$/ { in_block=0; printf("\0"); } 108 ')