• [gentoo-dev] [PATCH v2 1/2] sec-keys.eclass: new eclass

    From Eli Schwartz@21:1/5 to All on Thu Nov 28 05:40:01 2024
    The current state of verify-sig support is a bit awkward. We rely on
    validating distfiles against a known trusted keyring, but creating the
    known trusted keyring is basically all manual verification. We somehow
    decide an ascii armored key is good enough without any portage
    assistance, then arrange to download it and trust it by Manifest hash.
    How do we know when updating a key is actually safe?

    This eclass handles the problem in a manner inspired in part by pacman.
    We require an eclass variable that lists all permitted PGP fingerprints,
    and the eclass is responsible checking that list against the keys we
    will install. It comes with a mechanism for computing SRC_URI for a
    couple of well known locations, or you can append your own in the
    ebuild.

    Key rotations, both expected and malicious, are easily detected by
    checking the git log for changes to declared fingerprints in a bump. The
    former can be rationalized in the commit message. So can the latter, but
    in most cases those will be rejected during peer review.

    Signed-off-by: Eli Schwartz <eschwartz@gentoo.org>
    ---
    eclass/sec-keys.eclass | 197 +++++++++++++++++++++++++++++++++++++++++
    1 file changed, 197 insertions(+)
    create mode 100644 eclass/sec-keys.eclass

    diff --git a/eclass/sec-keys.eclass b/eclass/sec-keys.eclass
    new file mode 100644
    index 000000000000..7ea4d34a8c1c
    --- /dev/null
    +++ b/eclass/sec-keys.eclass
    @@ -0,0 +1,197 @@
    +# Copyright 2024 Gentoo Authors
    +# Distributed under the terms of the GNU General Public License v2
    +
    +# @ECLASS: sec-keys.eclass
    +# @MAINTAINER:
    +# Eli Schwartz <eschwartz@gentoo.org>
    +# @AUTHOR:
    +# Eli Schwartz <eschwartz@gentoo.org>
    +# @SUPPORTED_EAPIS: 8
    +# @BLURB: Provides a uniform way of handling ebuilds which package PGP key material
    +# @DESCRIPTION:
    +# This eclass provides a streamlined approach to finding suitable source material
    +# for OpenPGP keys used by the verify-sig eclass. Its primary purpose is to permit
    +# developers to easily and securely package new sec-keys/* packages. The eclass
    +# removes the risk of developers accidentally packaging m
  • From =?UTF-8?Q?Micha=C5=82_G=C3=B3rny?=@21:1/5 to Eli Schwartz on Thu Nov 28 14:20:01 2024
    On Wed, 2024-11-27 at 23:32 -0500, Eli Schwartz wrote:
    +# @ECLASS_VARIABLE: SEC_KEYS_VALIDPGPKEYS
    +# @PRE_INHERIT
    +# @DEFAULT_UNSET
    +# @DESCRIPTION:
    +# Mapping of fingerprints, name, and optional location of PGP keys to include,

    So "location" or "locations", plural?

    +# separated by colons. The allowed values for a location are:
    +#
    +# - gentoo -- fetch key by fingerprint from https://keys.gentoo.org
    +#
    +# - github -- fetch key from github.com/${name}.pgp
    +#
    +# - openpgp -- fetch key by fingerprint from https://keys.openpgp.org
    +#
    +# - ubuntu -- fetch key by fingerprint from http://keyserver.ubuntu.com (the default)

    I'd go without a default. Typing 6 more letters doesn't cost anything,
    and makes the contents more consistent. Also saves us from regretting
    having chosen a bad default in the future.

    +#
    +# - none -- do not add to SRC_URI, the ebuild will provide a custom download location

    Perhaps "manual"? "None" sounds like there would be no key at all.

    +_sec_keys_set_globals() {
    + if [[ ${SEC_KEYS_VALIDPGPKEYS[*]} ]]; then
    + local key fingerprint name loc locations=() remote
    + for key in "${SEC_KEYS_VALIDPGPKEYS[@]}"; do
    + fingerprint=${key%%:*}
    + name=${key#${fingerprint}:}; name=${name%%:*}
    + IFS=, read -r -a locations <<<"${key##*:}"
    + [[ ${locations[@]} ]] || locations=(ubuntu)
    + for loc in "${locations[@]}"; do
    + case ${loc} in
    + gentoo) remote="https://keys.gentoo.org/pks/lookup?op=get&search=0x${fingerprint}";;
    + github) remote="https://github.com/${name}.gpg";;
    + openpgp) remote="https://keys.openpgp.org/vks/v1/by-fingerprint/${fingerprint}";;
    + ubuntu) remote="https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x${fingerprint}";;
    + # provided via manual SRC_URI
    + none) continue;;
    + *) die "${ECLASS}: unknown PGP key remote: ${loc}";;
    +

    Stray empty line.

    + esac
    + SRC_URI+="
    + ${remote} -> openpgp-keys-${name}-${loc}-${PV}.asc
    + "
    + done
    + done
    + fi
    +}
    +_sec_keys_set_globals
    +unset -f _sec_keys_set_globals
    +
    +IUSE="test"
    +PROPERTIES="test_network"
    +RESTRICT="test"
    +
    +BDEPEND="
    + app-crypt/gnupg
    + test? ( app-crypt/pgpdump )
    +"
    +S=${WORKDIR}
    +
    +LICENSE="public-domain"
    +SLOT="0"

    Please keep ebuildy variables in the standard/skel order, or at least
    as close to it as you can get.

    +# @FUNCTION: sec-keys_src_compile
    +# @DESCRIPTION:
    +# Default src_compile override that imports all public keys into a keyring, +# and validates that they are listed in SEC_KEYS_VALIDPGPKEYS. +sec-keys_src_compile() {
    + local -x GNUPGHOME=${WORKDIR}/gnupg
    + mkdir -m700 -p "${GNUPGHOME}" || die
    +
    + pushd "${DISTDIR}" >/dev/null || die
    + gpg --import ${A} || die
    + popd >/dev/null || die
    +
    + local line imported_keys=() found=0
    + while IFS=: read -r -a line; do
    + if [[ ${line[0]} = pub ]]; then

    Please use '==' in ebuilds and eclasses.

    + # new key
    + found=0
    + elif [[ ${found} = 0 && ${line[0]} = fpr ]]; then
    + # primary fingerprint
    + imported_keys+=("${line[9]}")
    + found=1
    + fi
    + done < <(gpg --batch --list-keys --keyid-format=long --with-colons || die)

    Why do you need --keyid-format? You're using fingerprints only, aren't
    you?

    +
    + printf '%s\n' "${imported_keys[@]}" | sort > imported_keys.list || die + printf '%s\n' "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}" | sort > allowed_keys.list || die
    +
    + local extra_keys=($(comm -23 imported_keys.list allowed_keys.list || die))
    + local missing_keys=($(comm -13 imported_keys.list allowed_keys.list || die))
    +
    + if [[ ${#extra_keys[@]} != 0 ]]; then
    + die "too many keys found. Suspicious keys: ${extra_keys[@]}"

    The first sentence is not capitalized.

    + fi
    + if [[ ${#missing_keys[@]} != 0 ]]; then
    + die "too few keys found. Unavailable keys: ${missing_keys[@]}" + fi
    +}
    +
    +
    +sec-keys_src_test() {
    + local -x GNUPGHOME=${WORKDIR}/gnupg
    + local key fingerprint name server
    + local gpg_command=(gpg --export-options export-minimal)
    +
    + for fingerprint in "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}"; do
    + "${gpg_command[@]}" --export "${fingerprint}" | pgpdump > "${fingerprint}.pgpdump" || die
    + done
    +
    + # Best-effort attempt to check for updates. keyservers can and usually do
    + # fail for weird reasons, (such as being unable to import a key without a
    + # uid) as well as normal reasons, like the key being exclusive to a
    + # different keyserver. this isn't a reason to fail src_test.

    Well, I dare say that if refreshing against the server specified
    as the reference source fails, that would count as a reason to fail.
    Consider the case of someone removing a compromised key instead
    of revoking it.

    + for server in keys.gentoo.org keys.openpgp.org keyserver.ubuntu.com; do + gpg --refresh-keys --keyserver "hkps://${server}"
    + done
    + for key in "${SEC_KEYS_VALIDPGPKEYS[@]}"; do
    + if [[ ${key##*:} = *github* ]]; then
    + name=${key#*:}; name=${name%%:*}
    + wget -qO- https://github.com/${name}.gpg | gpg --import || die
    + fi
    + done
    +
    + for fingerprint in "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}"; do
    + "${gpg_command[@]}" --export "${fingerprint}" | pgpdump > "${fingerprint}.pgpdump.new" || die
    + diff -u "${fingerprint}.pgpdump" "${fingerprint}.pgpdump.new" || die "updates available for PGP key: ${fingerprint}"
    + done
    +
    +}
    +
    +# @FUNCTION: sec-keys_src_install
    +# @DESCRIPTION:
    +# Default src_install override that minifies and exports all PGP public keys +# into an ascii-armored keyfile installed to the standard /usr/share/openpgp-keys.
    +sec-keys_src_install() {
    + local -x GNUPGHOME=${WORKDIR}/gnupg
    + local fingerprint
    + local gpg_command=(gpg --no-permission-warning --export-options export-minimal)
    +
    + for fingerprint in "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}"; do
    + local uids=()
    + mapfile -t uids < <("${gpg_command[@]}" --list-key --with-colons ${fingerprint} | awk -F: '/^uid/{print $10}' || die)
    + edo "${gpg_command[@]}" "${uids[@]/#/--comment=}" --export --armor "${fingerprint}" >> ${PN#openpgp-keys-}.asc
    + done

    That looks like something you could do in src_compile() already.

    Also, I'm confused by the purpose of this whole logic. After all, you
    have already verified that there are no stray keys in the keyring,
    right? So why not just export the whole thing?


    --
    Best regards,
    Michał Górny


    -----BEGIN PGP SIGNATURE-----

    iQFGBAABCgAwFiEEx2qEUJQJjSjMiybFY5ra4jKeJA4FAmdIa6kSHG1nb3JueUBn ZW50b28ub3JnAAoJEGOa2uIyniQOVhgH/2j0WF3p7/pDuQtUXG1ZI8JnP1qfsqhK pQPN/f4iOh5QHc30IlC1lqEl80H5yZiSyDPxoJLABDWl99DcFuOuuKGEJD5nM1ZW 07VZEUMNYl9aMDA310AV7MidMUVqmpECYVTOfFLcHlLWHqpcsjisFQ7ryUJHztVP sfOyR1HEVYTSVqOaFOiGmatk1qTYylOkC0dEaTgCOsuVRThoe5G1Ac4HUVDAenTH YIDRFp3K/p9/h2teK3YxaTTAGp2ELYB/5koN9rszaXIhvEZ3iLAXndwzpwqDlk74 XnF13DneHclKR2sz23qJgLqd+le/AZ4jX+LTEV/Nu6FGfu+m6Qmvco0=
    =qLyG
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Eli Schwartz@21:1/5 to All on Thu Nov 28 16:40:02 2024
    This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --------------0oN1hDSNgCKaHqxfMvR0XsyR
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: quoted-printable

    On 11/28/24 8:10 AM, Michał Górny wrote:
    On Wed, 2024-11-27 at 23:32 -0500, Eli Schwartz wrote:
    +# @ECLASS_VARIABLE: SEC_KEYS_VALIDPGPKEYS
    +# @PRE_INHERIT
    +# @DEFAULT_UNSET
    +# @DESCRIPTION:
    +# Mapping of fingerprints, name, and optional location of PGP keys to include,

    So "location" or "locations", plural?


    Fixed.


    +# separated by colons. The allowed values for a location are:
    +#
    +# - gentoo -- fetch key by fingerprint from https://keys.gentoo.org
    +#
    +# - github -- fetch key from github.com/${name}.pgp
    +#
    +# - openpgp -- fetch key by fingerprint from https://keys.openpgp.org
    +#
    +# - ubuntu -- fetch key by fingerprint from http://keyserver.ubuntu.com (the default)

    I'd go without a default. Typing 6 more letters doesn't cost anything,
    and makes the contents more consistent. Also saves us from regretting
    having chosen a bad default in the future.

    +#
    +# - none -- do not add to SRC_URI, the ebuild will provide a custom download location

    Perhaps "manual"? "None" sounds like there would be no key at all.


    Maybe I could just document as a recommendation to use ubuntu. Other
    sources are likely to be extremely unreliable, unfortunately.
    openpgp.org only works if the key owner manually verifies their email,
    for example.


    + case ${loc} in
    + gentoo) remote="https://keys.gentoo.org/pks/lookup?op=get&search=0x${fingerprint}";;
    + github) remote="https://github.com/${name}.gpg";;
    + openpgp) remote="https://keys.openpgp.org/vks/v1/by-fingerprint/${fingerprint}";;
    + ubuntu) remote="https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x${fingerprint}";;
    + # provided via manual SRC_URI
    + none) continue;;
    + *) die "${ECLASS}: unknown PGP key remote: ${loc}";;
    +

    Stray empty line.


    Fixed.


    +S=${WORKDIR}
    +
    +LICENSE="public-domain"
    +SLOT="0"

    Please keep ebuildy variables in the standard/skel order, or at least
    as close to it as you can get.


    Fixed.


    +# @FUNCTION: sec-keys_src_compile
    +# @DESCRIPTION:
    +# Default src_compile override that imports all public keys into a keyring, >> +# and validates that they are listed in SEC_KEYS_VALIDPGPKEYS.
    +sec-keys_src_compile() {
    + local -x GNUPGHOME=${WORKDIR}/gnupg
    + mkdir -m700 -p "${GNUPGHOME}" || die
    +
    + pushd "${DISTDIR}" >/dev/null || die
    + gpg --import ${A} || die
    + popd >/dev/null || die
    +
    + local line imported_keys=() found=0
    + while IFS=: read -r -a line; do
    + if [[ ${line[0]} = pub ]]; then

    Please use '==' in ebuilds and eclasses.


    ...


    + # new key
    + found=0
    + elif [[ ${found} = 0 && ${line[0]} = fpr ]]; then
    + # primary fingerprint
    + imported_keys+=("${line[9]}")
    + found=1
    + fi
    + done < <(gpg --batch --list-keys --keyid-format=long --with-colons || die)

    Why do you need --keyid-format? You're using fingerprints only, aren't
    you?


    I'm used to it mattering in various contexts and added it instinctively.
    You're right, it doesn't do anything here.


    +
    + printf '%s\n' "${imported_keys[@]}" | sort > imported_keys.list || die >> + printf '%s\n' "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}" | sort > allowed_keys.list || die
    +
    + local extra_keys=($(comm -23 imported_keys.list allowed_keys.list || die))
    + local missing_keys=($(comm -13 imported_keys.list allowed_keys.list || die))
    +
    + if [[ ${#extra_keys[@]} != 0 ]]; then
    + die "too many keys found. Suspicious keys: ${extra_keys[@]}"

    The first sentence is not capitalized.


    Fixed.


    + fi
    + if [[ ${#missing_keys[@]} != 0 ]]; then
    + die "too few keys found. Unavailable keys: ${missing_keys[@]}" >> + fi
    +}
    +
    +
    +sec-keys_src_test() {
    + local -x GNUPGHOME=${WORKDIR}/gnupg
    + local key fingerprint name server
    + local gpg_command=(gpg --export-options export-minimal)
    +
    + for fingerprint in "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}"; do
    + "${gpg_command[@]}" --export "${fingerprint}" | pgpdump > "${fingerprint}.pgpdump" || die
    + done
    +
    + # Best-effort attempt to check for updates. keyservers can and usually do
    + # fail for weird reasons, (such as being unable to import a key without a
    + # uid) as well as normal reasons, like the key being exclusive to a
    + # different keyserver. this isn't a reason to fail src_test.

    Well, I dare say that if refreshing against the server specified
    as the reference source fails, that would count as a reason to fail. Consider the case of someone removing a compromised key instead
    of revoking it.


    This doesn't test a useful property.

    People cannot "remove" compromised keys from a keyserver to begin with.
    If they did, then checking to build the package with GENTOO_MIRRORS= DISTDIR=$(mktemp -d) is a significantly more useful test.

    Removing a key for whatever reason, doesn't tell you why it was removed,
    or even who removed it. It is also not how the PGP standard says you are supposed to handle a *compromised* key. It's not like GnuPG will delete
    keys from your keyring if the server doesn't possess it anymore... there
    is actually no such thing as a user of PGP that would be correctly
    served by someone removing a compromised key in the hopes that those
    users would interpret it as an indicator of compromise.

    In exchange for no assurances whatsoever, the code would become a lot
    more complicated. As I already said, gpg exiting with something other
    than 0 for success can mean many things and there's no good way to
    figure out what it did in fact mean.

    I'm going to need a better argument if you want me to change this.


    +sec-keys_src_install() {
    + local -x GNUPGHOME=${WORKDIR}/gnupg
    + local fingerprint
    + local gpg_command=(gpg --no-permission-warning --export-options export-minimal)
    +
    + for fingerprint in "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}"; do
    + local uids=()
    + mapfile -t uids < <("${gpg_command[@]}" --list-key --with-colons ${fingerprint} | awk -F: '/^uid/{print $10}' || die)
    + edo "${gpg_command[@]}" "${uids[@]/#/--comment=}" --export --armor "${fingerprint}" >> ${PN#openpgp-keys-}.asc
    + done

    That looks like something you could do in src_compile() already.


    Perhaps. But it felt like exporting keys is work that is conceptually
    part of installing, in much the way that running a meson project's
    `meson install` step does more than just copy files into ${D} -- it also processes those files in order to do things like patch the rpath.

    I guess I am not too attached to either approach.


    Also, I'm confused by the purpose of this whole logic. After all, you
    have already verified that there are no stray keys in the keyring,
    right? So why not just export the whole thing?


    Because this is doing additional steps that aren't just exporting the
    whole thing?


    --
    Eli Schwartz

    --------------0oN1hDSNgCKaHqxfMvR0XsyR--

    -----BEGIN PGP SIGNATURE-----

    wnsEABYIACMWIQTnFNnmK0TPZHnXm3qEp9ErcA0vVwUCZ0iOBAUDAAAAAAAKCRCEp9ErcA0vV978 APoCD/YpE7pL9nVYQkpeNAFyjQ0lQjsm0Hj1eNj6XldbCgD/R0FPzql12zKpK5wQaIjaHPD815q1 U7GTVFVevWraIAk=
    =gcb2
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Sam James@21:1/5 to Eli Schwartz on Thu Nov 28 18:00:01 2024
    Eli Schwartz <eschwartz@gentoo.org> writes:

    On 11/28/24 8:10 AM, Michał Górny wrote:
    On Wed, 2024-11-27 at 23:32 -0500, Eli Schwartz wrote:

    That looks like something you could do in src_compile() already.


    Perhaps. But it felt like exporting keys is work that is conceptually
    part of installing, in much the way that running a meson project's
    `meson install` step does more than just copy files into ${D} -- it also processes those files in order to do things like patch the rpath.

    I guess I am not too attached to either approach.

    I think I very loosely prefer doing it in src_compile as it's
    "compilation" of the resulting files and then src_install just moving
    the bundle, but I hardly feel strongly about it at all and feel it's
    personal preference. Not worth the electrons ;)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From =?UTF-8?Q?Micha=C5=82_G=C3=B3rny?=@21:1/5 to Sam James on Thu Nov 28 18:10:01 2024
    On Thu, 2024-11-28 at 16:56 +0000, Sam James wrote:
    Eli Schwartz <eschwartz@gentoo.org> writes:

    On 11/28/24 8:10 AM, Michał Górny wrote:
    On Wed, 2024-11-27 at 23:32 -0500, Eli Schwartz wrote:

    That looks like something you could do in src_compile() already.


    Perhaps. But it felt like exporting keys is work that is conceptually
    part of installing, in much the way that running a meson project's
    `meson install` step does more than just copy files into ${D} -- it also processes those files in order to do things like patch the rpath.

    I guess I am not too attached to either approach.

    I think I very loosely prefer doing it in src_compile as it's
    "compilation" of the resulting files and then src_install just moving
    the bundle, but I hardly feel strongly about it at all and feel it's
    personal preference. Not worth the electrons ;)

    My point was mostly that you wouldn't have to start with GNUPGHOME
    again. Also, tests might be able to reuse the result then. Also, tests wouldn't be able to mess up src_install() (think of test-fail-continue
    too).

    --
    Best regards,
    Michał Górny


    -----BEGIN PGP SIGNATURE-----

    iQFGBAABCgAwFiEEx2qEUJQJjSjMiybFY5ra4jKeJA4FAmdIowkSHG1nb3JueUBn ZW50b28ub3JnAAoJEGOa2uIyniQOQGMH/31647MiJDatDXaOgkUr2IWFMeoAcSub 4h9o9piy3LGSceU9rxjapsVPu1Nc12cTM/IDrj2t6W8SqUkevpr03p0puPJ+q/L0 tZIDmOxBusu9OJFQ40v/cOyv6Q6f7HaxelqiqNUBcoJp6VkYJhlSk7grMa8ELMmL xuniuJnoEiIM2K3ZGFMnxdw9HhK/JB1HzHrezo3xjhAVUwmejP8l+iHPQvdCbqot /8suz7wVqPujdReVoyiMwP3PxBNkkgMqNiy6Jz8PO9tZQLw1kmHOuYu+w9M9KJiK OBtB1VSNFRwKaLgusyBSP+aTVYhylIMrfYRS28JMZWUf5mOmQl8rgRY=
    =9kc4
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From =?UTF-8?Q?Micha=C5=82_G=C3=B3rny?=@21:1/5 to Eli Schwartz on Thu Nov 28 17:50:01 2024
    On Thu, 2024-11-28 at 10:36 -0500, Eli Schwartz wrote:
    On 11/28/24 8:10 AM, Michał Górny wrote:

    +# separated by colons. The allowed values for a location are:
    +#
    +# - gentoo -- fetch key by fingerprint from https://keys.gentoo.org
    +#
    +# - github -- fetch key from github.com/${name}.pgp
    +#
    +# - openpgp -- fetch key by fingerprint from https://keys.openpgp.org +#
    +# - ubuntu -- fetch key by fingerprint from http://keyserver.ubuntu.com (the default)

    I'd go without a default. Typing 6 more letters doesn't cost anything,
    and makes the contents more consistent. Also saves us from regretting having chosen a bad default in the future.

    +#
    +# - none -- do not add to SRC_URI, the ebuild will provide a custom download location

    Perhaps "manual"? "None" sounds like there would be no key at all.


    Maybe I could just document as a recommendation to use ubuntu. Other
    sources are likely to be extremely unreliable, unfortunately.
    openpgp.org only works if the key owner manually verifies their email,
    for example.

    Yeah. I don't see why anyone would specify a non-working location (such
    as openpgp.org).

    + # new key
    + found=0
    + elif [[ ${found} = 0 && ${line[0]} = fpr ]]; then
    + # primary fingerprint
    + imported_keys+=("${line[9]}")
    + found=1
    + fi
    + done < <(gpg --batch --list-keys --keyid-format=long --with-colons || die)

    Why do you need --keyid-format? You're using fingerprints only, aren't you?


    I'm used to it mattering in various contexts and added it instinctively. You're right, it doesn't do anything here.

    Yeah. And for a minute, it made me worry that you're using long ids
    instead of fingerprints.

    + fi
    + if [[ ${#missing_keys[@]} != 0 ]]; then
    + die "too few keys found. Unavailable keys: ${missing_keys[@]}" + fi
    +}
    +
    +
    +sec-keys_src_test() {
    + local -x GNUPGHOME=${WORKDIR}/gnupg
    + local key fingerprint name server
    + local gpg_command=(gpg --export-options export-minimal)
    +
    + for fingerprint in "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}"; do
    + "${gpg_command[@]}" --export "${fingerprint}" | pgpdump > "${fingerprint}.pgpdump" || die
    + done
    +
    + # Best-effort attempt to check for updates. keyservers can and usually do
    + # fail for weird reasons, (such as being unable to import a key without a
    + # uid) as well as normal reasons, like the key being exclusive to a
    + # different keyserver. this isn't a reason to fail src_test.

    Well, I dare say that if refreshing against the server specified
    as the reference source fails, that would count as a reason to fail. Consider the case of someone removing a compromised key instead
    of revoking it.


    This doesn't test a useful property.

    People cannot "remove" compromised keys from a keyserver to begin with.
    If they did, then checking to build the package with GENTOO_MIRRORS= DISTDIR=$(mktemp -d) is a significantly more useful test.

    In fact, this is the kind of test I was originally thinking of -- i.e. literally refetching the file manually and seeing if the minimal export differs...

    +sec-keys_src_install() {
    + local -x GNUPGHOME=${WORKDIR}/gnupg
    + local fingerprint
    + local gpg_command=(gpg --no-permission-warning --export-options export-minimal)
    +
    + for fingerprint in "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}"; do
    + local uids=()
    + mapfile -t uids < <("${gpg_command[@]}" --list-key --with-colons ${fingerprint} | awk -F: '/^uid/{print $10}' || die)
    + edo "${gpg_command[@]}" "${uids[@]/#/--comment=}" --export --armor "${fingerprint}" >> ${PN#openpgp-keys-}.asc
    + done

    That looks like something you could do in src_compile() already.


    Perhaps. But it felt like exporting keys is work that is conceptually
    part of installing, in much the way that running a meson project's
    `meson install` step does more than just copy files into ${D} -- it also processes those files in order to do things like patch the rpath.

    I guess I am not too attached to either approach.


    Also, I'm confused by the purpose of this whole logic. After all, you
    have already verified that there are no stray keys in the keyring,
    right? So why not just export the whole thing?


    Because this is doing additional steps that aren't just exporting the
    whole thing?


    Then perhaps you should add an explanatory comment instead of expecting
    people to catch that from a command so long it doesn't fit on people's
    screens.

    --
    Best regards,
    Michał Górny


    -----BEGIN PGP SIGNATURE-----

    iQFGBAABCgAwFiEEx2qEUJQJjSjMiybFY5ra4jKeJA4FAmdInXUSHG1nb3JueUBn ZW50b28ub3JnAAoJEGOa2uIyniQO1kEH/jJw9pvr8kCOqwLwTRpuMvgqQQlsUv+R KxqI5IU8kwU86TaDMvMyx4Apld+qvr8YTPhInfCcDZlcGEs75yxtlD0Z0KkoY81V Ye/BBIWftspaMWTBVHYS2PAqXVDWH6AAk61/uq+8vKojehB3kLmq3rZJjTE2a0gO 0BuwNq6vGCSKCYP9ZXFvtOH/B5yF6nd0diTNlgUmKbWUQ0IBSv4qEsJ/LJhRxd/o Y8CJHWA47o46EVq8XTsX5QvobDFaO7yrjT+X5eDE7UzF0Sb9TjLs4Dr1j3nAFIOV rpwOYRoK+FO7p00W9O4lltxyAkcl6pLmkWZ74OUyjF4TO0S/sxVb90s=
    =R9HB
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Sam James@21:1/5 to mgorny@gentoo.org on Thu Nov 28 18:30:01 2024
    Michał Górny <mgorny@gentoo.org> writes:

    On Thu, 2024-11-28 at 16:56 +0000, Sam James wrote:
    Eli Schwartz <eschwartz@gentoo.org> writes:

    On 11/28/24 8:10 AM, Michał Górny wrote:
    On Wed, 2024-11-27 at 23:32 -0500, Eli Schwartz wrote:

    That looks like something you could do in src_compile() already.


    Perhaps. But it felt like exporting keys is work that is conceptually
    part of installing, in much the way that running a meson project's
    `meson install` step does more than just copy files into ${D} -- it also >> > processes those files in order to do things like patch the rpath.

    I guess I am not too attached to either approach.

    I think I very loosely prefer doing it in src_compile as it's
    "compilation" of the resulting files and then src_install just moving
    the bundle, but I hardly feel strongly about it at all and feel it's
    personal preference. Not worth the electrons ;)

    My point was mostly that you wouldn't have to start with GNUPGHOME
    again. Also, tests might be able to reuse the result then. Also, tests wouldn't be able to mess up src_install() (think of test-fail-continue
    too).

    Ah, test-fail-continue is a good point.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Eli Schwartz@21:1/5 to Robin H. Johnson on Fri Nov 29 20:10:01 2024
    This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --------------t8sgxBdUAK29sP81XGn2Ikxc
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: quoted-printable

    On 11/29/24 1:31 PM, Robin H. Johnson wrote:
    From a technical perspective, that depends on the keyserver design.

    But the canonical "why" is GDPR Article 17 - right-to-erasure.

    Hockeypuck even ships a script to make it easy for admins to delete
    keys: https://github.com/hockeypuck/hockeypuck/blob/5cc0fffe46f44986cbf78a554ab482e3baaa5143/contrib/docker-compose/standalone/README.md?plain=1#L177-L190

    There is another more obvious reason why a key might vanish from a
    keyserver: ephemeral & eventually consistent state


    Indeed, but that just reinforces my point that this doesn't represent a
    failing test. :)

    GDPR argumentation aside and practicalities alone, PGP keys for
    developers of software packaged in linux distributions *cannot* be
    forgotten, period, since they exist in tons of places including
    committed to git as *.asc files in multiple distros' package sources.

    And user-requested deletion would anyways not be a test failure as the
    package is plainly fine and can continue to be verified. It's possible
    for us to be independently asked to make a commit that removes the key
    in question from ::gentoo, but that's a separate story.

    Ephemeral state is an even greater indication of why refreshes should be expected to fail without failing the test :) since an ephemeral state
    that is not yet consistent does not mean the key has disappeared or that
    it needs to be updated.


    --
    Eli Schwartz

    --------------t8sgxBdUAK29sP81XGn2Ikxc--

    -----BEGIN PGP SIGNATURE-----

    wnsEABYIACMWIQTnFNnmK0TPZHnXm3qEp9ErcA0vVwUCZ0oPwgUDAAAAAAAKCRCEp9ErcA0vV1Yw AQDuZEuWWcUE6fa4DPdlS180hqpKizEuRCtfL9VCHygCtAEAoByq5LPhi5afPW09sALe3Xa5/cqZ S3OiouyDVbY9nAg=
    =GB38
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin H. Johnson@21:1/5 to Eli Schwartz on Fri Nov 29 19:40:01 2024
    On Thu, Nov 28, 2024 at 10:36:36AM -0500, Eli Schwartz wrote:
    This doesn't test a useful property.

    People cannot "remove" compromised keys from a keyserver to begin with.
    If they did, then checking to build the package with GENTOO_MIRRORS= DISTDIR=$(mktemp -d) is a significantly more useful test.
    From a technical perspective, that depends on the keyserver design.

    But the canonical "why" is GDPR Article 17 - right-to-erasure.

    Hockeypuck even ships a script to make it easy for admins to delete
    keys: https://github.com/hockeypuck/hockeypuck/blob/5cc0fffe46f44986cbf78a554ab482e3baaa5143/contrib/docker-compose/standalone/README.md?plain=1#L177-L190

    There is another more obvious reason why a key might vanish from a
    keyserver: ephemeral & eventually consistent state

    The SKS server implementation is sufficiently unreliable** for
    keys.gentoo.org that one node occasionally corrupts it's database, and I
    have a script that rebuilds it. If a key is uploaded to a node, and NOT
    yet propagated to other nodes before the corruption event, this could
    lead to the appearance of a key being removed.

    The SKS network, when it still ran, also provided an eventually
    consistent behaviour, such that a series of rapid queries to the DNS
    rotation might not always return the same data for a given key if
    changes to that key were in flight.

    ** Yes, one of the gentoo nodes is running Hockeypuck now, and I hope to replace all of SKS with Hockeypuck in future, but it's not quite the
    same yet.

    --
    Robin Hugh Johnson
    Gentoo Linux: Dev, Infra Lead, Foundation Treasurer
    E-Mail : robbat2@gentoo.org
    GnuPG FP : 11ACBA4F 4778E3F6 E4EDF38E B27B944E 34884E85
    GnuPG FP : 7D0B3CEB E9B85B1F 825BCECF EE05E6F6 A48F6136

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v2
    Comment: Robbat2 @ Orbis-Terrarum Networks - The text below is a digital signature. If it doesn't make any sense to you, ignore it.

    iQKTBAABCgB9FiEEveu2pS8Vb98xaNkRGTlfI8WIJsQFAmdKCIZfFIAAAAAALgAo aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEJE RUJCNkE1MkYxNTZGREYzMTY4RDkxMTE5Mzk1RjIzQzU4ODI2QzQACgkQGTlfI8WI JsROUhAAqTI5u7CwthteDxJUcHplpEQFSGLmQ73RO5yiqX3RRkbq6tZQgUhm5wsh SmsLaDx3Q5LKxWCevaDFXtKqL9DctEkD5QSw3td3PHsg7nNU77Upd/f7Tps9GEhz aQkcInSjM5ndQeFFAx6I5kFuBjRET7ZzCs8ITMs7VlDZIRnoekWVqllwIFAy649r NAZE1qXgjksPDx3W9ghLqkCjyBMZhzwPDunvXhnkb8nSOE0oBn4BYcu57v78IHuh TXxCFQWjg+l78bFAfWi/C8oJN+GGtBIeRYzaHEEj+xFEepnEPz/PeJh9hAZGsW9b wEjyHfUa9ZlK7dH5BdNwz/JY0Hg7L3DpO5ozEuSrNyfHOnmSTIPJ+eJGEvaUxNsy YCvEByr1nsWfgcG8E9uS