From: DaanDeMeyer Date: Thu, 21 Aug 2025 11:47:03 +0000 (+0200) Subject: fedora: Rework rawhide GPG key logic X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b1d66c88d09b2bce0e28b50e2d14d867dffeb665;p=thirdparty%2Fmkosi.git fedora: Rework rawhide GPG key logic - Drop secondary key logic as looking at https://github.com/rpm-software-management/distribution-gpg-keys/tree/main/keys/fedora, this hasn't been used for a long time. - If repository key fetching is enabled, always look up the key remotely as e.g. on CentOS 9 or so the rawhide symlink might be horribly outdated. - If not using repository key fetching, Use all local keys newer than the rawhide key as well to maximize the chances of including the current rawhide key. - Resolve symlinks within the sandbox in find_rpm_gpgkey() as we might not be able to resolve the symlinks outside of the sandbox. --- diff --git a/mkosi/distributions/fedora.py b/mkosi/distributions/fedora.py index 81a4716c4..88440bd01 100644 --- a/mkosi/distributions/fedora.py +++ b/mkosi/distributions/fedora.py @@ -17,7 +17,7 @@ from mkosi.distributions import ( from mkosi.installer.dnf import Dnf from mkosi.installer.rpm import RpmRepository, find_rpm_gpgkey, setup_rpm from mkosi.log import die -from mkosi.util import startswith, tuplify +from mkosi.util import tuplify DISTRIBUTION_GPG_KEYS_UPSTREAM = ( "https://raw.githubusercontent.com/rpm-software-management/distribution-gpg-keys/main/keys/fedora" @@ -35,95 +35,62 @@ def read_remote_rawhide_key_symlink(context: Context) -> str: @tuplify def find_fedora_rpm_gpgkeys(context: Context) -> Iterable[str]: - key1 = find_rpm_gpgkey( - context, key=f"RPM-GPG-KEY-fedora-{context.config.release}-primary", required=False - ) - key2 = find_rpm_gpgkey( - context, key=f"RPM-GPG-KEY-fedora-{context.config.release}-secondary", required=False + versionre = re.compile(r"RPM-GPG-KEY-fedora-(\d+)-primary") + + if context.config.release == "rawhide" and context.config.repository_key_fetch: + # Rawhide is a moving target and signed with a different GPG key every time a new Fedora release is + # done. In distribution-gpg-keys this is modeled by a symlink that is continuously updated to point + # to the current GPG key for rawhide. Of course, this symlink gets outdated when using a locally + # installed distribution-gpg-keys package. If we're allowed to look up GPG keys remotely, look up the + # current rawhide version remotely and use the associated remote key. + key = read_remote_rawhide_key_symlink(context) + if not (rawhide_will_be := versionre.match(key)): + die(f"Missing Fedora version in remote rawhide key {key} from distribution-gpg-keys") + + version = int(rawhide_will_be.group(1)) + yield f"{DISTRIBUTION_GPG_KEYS_UPSTREAM}/RPM-GPG-KEY-fedora-{version}-primary" + + # Also use the N+1 key if it exists to avoid issues when rawhide has been moved to the next key but + # the rawhide symlink in distribution-gpg-keys hasn't been updated yet. + try: + with tempfile.TemporaryDirectory() as d: + curl( + context.config, + f"{DISTRIBUTION_GPG_KEYS_UPSTREAM}/RPM-GPG-KEY-fedora-{version + 1}-primary", + Path(d), + log=False, + ) + + yield f"{DISTRIBUTION_GPG_KEYS_UPSTREAM}/RPM-GPG-KEY-fedora-{version + 1}-primary" + except subprocess.CalledProcessError: + pass + + return + + key = find_rpm_gpgkey( + context, + key=f"RPM-GPG-KEY-fedora-{context.config.release}-primary", + fallback=f"{DISTRIBUTION_GPG_KEYS_UPSTREAM}/RPM-GPG-KEY-fedora-{context.config.release}-primary", ) - versionre = re.compile(r"RPM-GPG-KEY-fedora-(\d+)-(primary|secondary)") - - if key1: - # During branching, there is always a kerfuffle with the key transition. - # For Rawhide, try to load the N+1 key, just in case our local configuration - # still indicates that Rawhide==N, but really Rawhide==N+1. - if context.config.release == "rawhide" and (rhs := startswith(key1, "file://")): - version_file = Path(rhs) - version = 0 - # If the local file points to rawhide, it is usually a symlink in the distribution-gpg-keys - # package that points to some released key, so we can extract the version from the key. - # If the local file is a release, we can extract the version directly. - if ( - version_file.name == "RPM-GPG-KEY-fedora-rawhide-primary" - and version_file.is_symlink() - and (rawhide_will_be := versionre.match(version_file.readlink().name)) - ): - version = int(rawhide_will_be.group(1)) - elif m := versionre.match(version_file.name): - version = int(m.group(1)) - - if version: - if key3 := find_rpm_gpgkey( - context, - key=f"RPM-GPG-KEY-fedora-{version + 1}-primary", - required=False, - ): - yield key3 - - # The rawhide key can also not be a symlink and we end up with the wrong version so far. So let's - # cheat and look up the version remotely, but look for the version we get in the keys that exist - # locally. - remote_rawhide_version = read_remote_rawhide_key_symlink(context) - if key4 := find_rpm_gpgkey(context, key=remote_rawhide_version, required=False): - yield key4 - - # Same as above, the symlink in distribution-gpg-keys might not have been updated yet to point to - # the new rawhide key when branching happens, so try to load the N+1 key as well. - if m := versionre.match(remote_rawhide_version): - version = int(m.group(1)) - - if key5 := find_rpm_gpgkey( - context, - key=f"RPM-GPG-KEY-fedora-{version + 1}-primary", - required=False, - ): - yield key5 - - yield key1 - - if key2: - yield key2 - - if not key1 and not key2: - if not context.config.repository_key_fetch: - die( - "Fedora GPG keys not found in /usr/share/distribution-gpg-keys", - hint="Make sure the distribution-gpg-keys package is installed", - ) + yield key - if context.config.release == "rawhide": - remote_rawhide_version = read_remote_rawhide_key_symlink(context) - yield f"{DISTRIBUTION_GPG_KEYS_UPSTREAM}/{remote_rawhide_version}" - - # Same dance as above - if m := versionre.match(remote_rawhide_version): - version = int(m.group(1)) - - try: - with tempfile.TemporaryDirectory() as d: - curl( - context.config, - f"{DISTRIBUTION_GPG_KEYS_UPSTREAM}/RPM-GPG-KEY-fedora-{version + 1}-primary", - Path(d), - log=False, - ) - - yield f"{DISTRIBUTION_GPG_KEYS_UPSTREAM}/RPM-GPG-KEY-fedora-{version + 1}-primary" - except subprocess.CalledProcessError: - pass - else: - yield "https://fedoraproject.org/fedora.gpg" + if context.config.release == "rawhide" and (rawhide_will_be := versionre.match(Path(key).name)): + # When querying the rawhide version remotely, we add the N+1 key as the symlink might not have been + # updated yet. We do expect the symlink update to happen in reasonable time so we only add the N+1 + # key. When using a locally installed distribution-gpg-keys package on older Fedora versions, there's + # a non-zero chance that rawhide might already be using the N+2 key. So let's play it safe and add + # all newer keys in this case. + version = int(rawhide_will_be.group(1)) + + i = 1 + while newerkey := find_rpm_gpgkey( + context, + key=f"RPM-GPG-KEY-fedora-{version + i}-primary", + required=False, + ): + yield newerkey + i += 1 class Installer(DistributionInstaller): diff --git a/mkosi/installer/rpm.py b/mkosi/installer/rpm.py index 38675ae40..d9496d7bd 100644 --- a/mkosi/installer/rpm.py +++ b/mkosi/installer/rpm.py @@ -61,7 +61,7 @@ def find_rpm_gpgkey( paths = ( run( - ["bash", "-c", rf"shopt -s nullglob && printf '%s\n' {' '.join(globs)}"], + ["bash", "-c", rf"shopt -s nullglob && printf '%s\n' {' '.join(globs)} | xargs -r readlink -f"], sandbox=context.sandbox(), stdout=subprocess.PIPE, )