Sysop: | Amessyroom |
---|---|
Location: | Fayetteville, NC |
Users: | 40 |
Nodes: | 6 (0 / 6) |
Uptime: | 10:04:49 |
Calls: | 291 |
Files: | 910 |
Messages: | 76,421 |
+# @ECLASS_VARIABLE: SEC_KEYS_VALIDPGPKEYS
+# @PRE_INHERIT
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Mapping of fingerprints, name, and optional location of PGP keys to include,
+# 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)
+#
+# - none -- do not add to SRC_URI, the ebuild will provide a custom download location
+_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}";;
+
+ 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"
+# @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
+ # 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)
+
+ 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[@]}"
+ 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.
+ 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
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.
+ 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.
+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.
+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?
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.
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 ;)
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.
+ # 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.
+ 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.
+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?
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).
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
This doesn't test a useful property.From a technical perspective, that depends on the keyserver design.
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.