diff --git a/config.ini b/config.ini index db88523..da2b80c 100644 --- a/config.ini +++ b/config.ini @@ -236,6 +236,38 @@ extractor = kconfigs.rpm.RpmExtractor index = https://dl.fedoraproject.org/pub/fedora/linux/updates/38/Everything/aarch64/ key = RPM-GPG-KEY-fedora-38-primary +## Fedora Asahi Remix + +[fedora_asahi_39_aarch64] +name = Fedora Asahi Remix +version = 39 +arch = aarch64 +package = kernel-core +fetcher = kconfigs.rpm.RpmFetcher +extractor = kconfigs.rpm.RpmExtractor +index = https://download.copr.fedorainfracloud.org/results/@asahi/kernel/fedora-39-aarch64/ +key = asahi.gpg + +[fedora_asahi_40_aarch64] +name = Fedora Asahi Remix +version = 40 +arch = aarch64 +package = kernel-core +fetcher = kconfigs.rpm.RpmFetcher +extractor = kconfigs.rpm.RpmExtractor +index = https://download.copr.fedorainfracloud.org/results/@asahi/kernel/fedora-40-aarch64/ +key = asahi.gpg + +[fedora_asahi_rawhide_aarch64] +name = Fedora Asahi Remix +version = Rawhide +arch = aarch64 +package = kernel-core +fetcher = kconfigs.rpm.RpmFetcher +extractor = kconfigs.rpm.RpmExtractor +index = https://download.copr.fedorainfracloud.org/results/@asahi/kernel/fedora-rawhide-aarch64/ +key = asahi.gpg + ## CentOS x86_64 [centos7_x86_64] @@ -268,6 +300,16 @@ extractor = kconfigs.rpm.RpmExtractor index = https://mirror.stream.centos.org/9-stream/BaseOS/x86_64/os/ key = RPM-GPG-KEY-CentOS-Official +[centos9_hyperscale_x86_64] +name = CentOS Hyperscale +version = 9 +arch = x86_64 +package = kernel-core +fetcher = kconfigs.rpm.RpmFetcher +extractor = kconfigs.rpm.RpmExtractor +index = https://mirror.stream.centos.org/SIGs/9-stream/hyperscale/x86_64/packages-experimental/ +key = RPM-GPG-KEY-CentOS-SIG-HyperScale + ## CentOS aarch64 [centos8_aarch64] @@ -290,6 +332,16 @@ extractor = kconfigs.rpm.RpmExtractor index = https://mirror.stream.centos.org/9-stream/BaseOS/aarch64/os/ key = RPM-GPG-KEY-CentOS-Official +[centos9_hyperscale_aarch64] +name = CentOS Hyperscale +version = 9 +arch = aarch64 +package = kernel-core +fetcher = kconfigs.rpm.RpmFetcher +extractor = kconfigs.rpm.RpmExtractor +index = https://mirror.stream.centos.org/SIGs/9-stream/hyperscale/aarch64/packages-experimental/ +key = RPM-GPG-KEY-CentOS-SIG-HyperScale + ## Ubuntu x86_64 [ubuntu_focal_x86_64] diff --git a/gpg-keys/Makefile b/gpg-keys/Makefile index ad4e2a3..65eefe3 100644 --- a/gpg-keys/Makefile +++ b/gpg-keys/Makefile @@ -1,7 +1,7 @@ -SRC_KEYS := $(shell find . -type f -not -name '*.gpg' -not -name Makefile -not -name 'debian*' -not -name 'ubuntu-*') +SRC_KEYS := $(shell find . -type f -not -name '*.gpg' -not -name Makefile -not -name 'debian*' -not -name 'ubuntu-*' -not -name 'fedora-asahi*') BIN_KEYS := $(patsubst %,%.gpg,$(SRC_KEYS)) -all: $(BIN_KEYS) debian.gpg ubuntu.gpg +all: $(BIN_KEYS) debian.gpg ubuntu.gpg asahi.gpg %.gpg: % gpg --dearmor <$< >$@ @@ -13,3 +13,7 @@ debian.gpg: $(DEBIAN_KEYS) UBUNTU_KEYS := $(shell echo ubuntu-*) ubuntu.gpg: $(UBUNTU_KEYS) gpg --no-default-keyring --keyring=./$@ --import $^ || true + +ASAHI_KEYS := $(shell echo fedora-asahi*) +asahi.gpg: $(ASAHI_KEYS) + gpg --no-default-keyring --keyring=./$@ --import $^ || true diff --git a/gpg-keys/RPM-GPG-KEY-CentOS-SIG-HyperScale b/gpg-keys/RPM-GPG-KEY-CentOS-SIG-HyperScale new file mode 100644 index 0000000..ba49b19 --- /dev/null +++ b/gpg-keys/RPM-GPG-KEY-CentOS-SIG-HyperScale @@ -0,0 +1,32 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2.0.22 (GNU/Linux) + +mQENBGAFPdEBCADhXtzOEQcQnug15GHYeYIA9Nw/x96b4XliZFi2GDT7Jqu6njA8 +QJtKm8C4Hoc/DxOXcidxDJ/pu2pYwzxRpuIi0K7PA5lF08HgF7aZsxq0yiFRMCaS +qpp4NCw/Xj0VPohu7jICQhzalnfZjTk0zEneBnpE6jCSIDLdaH8+iC5F2KerEPjq ++SZOH/aVLdFVgPUbz7zwL7XMsmDT0M22J1zO4QmUTsVbkaqtSwtl/qkl3Eo2hF1x +ToiYa6CPn2rNnNUZ1xhW2l/hncE9w/kbmzALFKHEo+XUbKsihfp0UAenxNtm0k6E +FDQTZpJet/nIq+6t3LFmZiFJl8mcIaXm3o95ABEBAAG0ZUNlbnRPUyBIeXBlclNj +YWxlIFNJRyAoaHR0cHM6Ly93aWtpLmNlbnRvcy5vcmcvU3BlY2lhbEludGVyZXN0 +R3JvdXAvSHlwZXJzY2FsZSkgPHNlY3VyaXR5QGNlbnRvcy5vcmc+iQE5BBMBCgAj +AhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AFAmIgawoACgkQKgH6Kus9rEDB +5QgAk7U2F8HGcaC3FXdqHzkqsz0gFZ0gpJ+QSVJphiCSTpBLzerFZEDD64igXOLi +qL5OW8fJrKBqKeGCT/VRV3UZWlwfD7gomBHNB7zQRSGtCYxydadBJsbYlNiI8C2t +EnNsoNxBpZRoWuYzGG16yEHDF+HiY1UsFXwet/uMwkUvdsGVuRnvQjkG5P4hSFHK +8i7XjtWwizhD/OHWqot5R+UumzNYPK+DsDfUI1qpUzfKxblLuSZvJO6wHcI/k+NG +55lddWHHFoYfBDVIn6iqN110r8w3vEKeeLWv/5virITg/5iFIxfvuXyPpOQSFz6E +rwSz547blvqMljHkCp9NnumdIbkBDQRgBT3RAQgA4fFLaZ1HsK+K0fdLxdzRUB2S +8FfIuV1n53taP6OYzk5fPRf/vwXt7E0IUONvBd/z7LfkR/eGbdG3i+cQnN8fJjHZ +1DkziTK4Xjq7vgLIOGzONFQwWj5XKoTBpw2+cfEmqiBlFY5erVzgxrZXB0aZeY3w +vWW2haOBuTUynPcVsdoDCsO5SYgFX8tDmZRUIwsLYvS5gI9DLxO6mLQnXqZapWD6 +GeVw+eCL/EST3eimrsRGPaBWUTplHaVDT3hV+w7Yx5SfjDJxWUJAwl13+YGB6HvR +T5gJuSgJ5MUQDtBMVGUDsv4Br0YiBSytquAgAAcJ4gzCzqNal623c/soXio+xQAR +AQABiQEfBBgBCgAJAhsMBQJiIGsSAAoJECoB+irrPaxAAWkH/RzJ3ZvJYb2BSeii +sKza+SXUIJl2LPjUJ6q8dfI3ity0jEpWpKFxN4tYcp3B9LZAon3g0P/Gc5kftIb7 +7qAnlCkh+dt8RtCeWEvdnZlIiS/k5w3dogBHzr2L980QOdyFZAxv6bugzEPzh3Dm +rBbH9JzSx0c+weeLZdgtDdgIXiPgtrQfdPe4uxjx39zy/k4Lt6M1mKsuy872yn35 +EMUeQhb82If+4fQOcYOfjc2I3MBMTd8cz/s6ZKKR1QD7rms2JPx1KJfIxjCSRyOL +dFmDih7j+JmBz7IYFRWMqp8SR0MBkVIykZYomEChhKOD5vSXOVEq/CD0tN63dlhs +fnRBNE0= +=rDM7 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/gpg-keys/RPM-GPG-KEY-CentOS-SIG-HyperScale.gpg b/gpg-keys/RPM-GPG-KEY-CentOS-SIG-HyperScale.gpg new file mode 100644 index 0000000..0a3f8fb Binary files /dev/null and b/gpg-keys/RPM-GPG-KEY-CentOS-SIG-HyperScale.gpg differ diff --git a/gpg-keys/asahi.gpg b/gpg-keys/asahi.gpg new file mode 100644 index 0000000..a6ad361 Binary files /dev/null and b/gpg-keys/asahi.gpg differ diff --git a/gpg-keys/fedora-asahi b/gpg-keys/fedora-asahi new file mode 100644 index 0000000..4ddbe2f --- /dev/null +++ b/gpg-keys/fedora-asahi @@ -0,0 +1,19 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBGOYar0BCADQB8RQPYp4XG5syc1EA1AX97V3dWXhsLDrDP5nB9dMtqvA/G/3 +zTcPPBgd6Pj+0ooWgBfI7XTZ5TiDfKvclPggDFoBI7oND88S3hUsDmHcG/az5tMM +DdFhiMn7HeLBv8R1IC01rHv8S7ye+4cAe8BhC+w+OLjugkY7QWJme6nfGJsGL79z +AuFdITWZXB+8QTmol1smGj5oQKjloMII6QOEqnbRXFPackObkLRoT+o1RVv5F4PX +Aypy9C5eayyE7TryE3Vq9RiVFvMem8uczKOBAGSMBVtHddkCikCXx8LKAO5GXNdt +gGyUEnQSmKhTHkmCC6Tt3BkI5NSbLYXDOAMDABEBAAG0WEBhc2FoaV9mZWRvcmEt +cmVtaXgtYnJhbmRpbmcgKE5vbmUpIDxAYXNhaGkjZmVkb3JhLXJlbWl4LWJyYW5k +aW5nQGNvcHIuZmVkb3JhaG9zdGVkLm9yZz6JAVcEEwEIAEEWIQSeSvpCGfSg0Qg8 +szuj3GdRV9BIzgUCY5hqvQIbLwUJCWYBgAULCQgHAgIiAgYVCgkICwIEFgIDAQIe +BwIXgAAKCRCj3GdRV9BIzoj6CADM+ypFA+FHB9Pu1mbqkvfbwA3oyjz2hqANhtGq +4qgMA8f4mcRQLC1DgFTbPf5SHDG4mq+DhAbNmAOJD79PsSGyxoo9KZ0XUAKecD3F +G1OBrzHag7VEs0oCd4zXNGiOtZHlvNIRPMDIp4jo2AtgnpRClkv4b19dgWrDU+XX +oKgGPTX6Tg4gMxZnDZkPKwWjh7H0pxVhA9j5sNFMnRFMxS/AI474PNlZ/Uic6M68 +0UCX+jFSH6avjXEUMjElOKyvtRURvjza3p5FxkpHDJ0CQNUWQHtqmc6XnbWF8bqr +LirXVCK/rWyHEFMu9FmTGX+YXekMCEAvZ+j/vSbZ6zuztc+p +=yTWP +-----END PGP PUBLIC KEY BLOCK----- diff --git a/gpg-keys/fedora-asahi-kernel b/gpg-keys/fedora-asahi-kernel new file mode 100644 index 0000000..da2c625 --- /dev/null +++ b/gpg-keys/fedora-asahi-kernel @@ -0,0 +1,19 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBGOkthcBCACzf42xzD/VNVXlRxqpZqe1hF640rwJuLhveshiCY173+/l9zFP +WTGBU7g+ZPCS6faz6B8M+yzU3QPvtFi+srWs/dM+PnYBPSxZs6wxrKCGb13wTUSS +C+RX6mPppxpkHaG/Rj+rlHS0dGIKP39YTAIsnPv0Pgk2JufM+/s1k3xbQUARoV1N +n6V4Lh0Q3Q0MgJDnVnn7g8MTq01J8U8PqKs2vZqQKn836Q4E+KC8VtE79w/R5B9/ +BKGYExT/Jqy6xPKXaANkoaAObj6iVtgwsJlwtJtJAhu4KX7rUwSFWoSGClMiIMd6 +cPR8RUl7+HinCB5tygxjoA22S3U122DMVhQbABEBAAG0OkBhc2FoaV9rZXJuZWwg +KE5vbmUpIDxAYXNhaGkja2VybmVsQGNvcHIuZmVkb3JhaG9zdGVkLm9yZz6JAVcE +EwEIAEEWIQSeTfkTXTnd/8d7UU6y2HBOAMCOoAUCY6S2FwIbLwUJCWYBgAULCQgH +AgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRCy2HBOAMCOoNttCACTRLCKpMOFdK9i +YykRmQ9Xmwf+3J6d401S+7CdL4t2YystWa0DjESZnCZRwIAMgUUSrwUoEUf1xLKN +m6LRhZ64VZewZEs019S0ntpv9iuKd//6WUuexIH6kOuzDI+f5UGeRxC04cvnNkh/ +g33+hgaha6s1+Md3j6ymM2qJsba4oqmCk8BfZPp31Gi4Gd13Uq9a5hinSxoYTaOE +UcXiTFrOEqwztEjOhJiwXCDA/89VUe+fYjqpGOqvzWW+UUatpt8LcVhTEcvUDSTu +d2j4lx2XIZ58Tg0oWT6iczWx9kYR02obk49KpbMfWyE/cEjj0MNNTmqX6/bvSBv8 +ohmhxOub +=X76U +-----END PGP PUBLIC KEY BLOCK----- diff --git a/kconfigs/rpm.py b/kconfigs/rpm.py index 20193cf..e293e08 100644 --- a/kconfigs/rpm.py +++ b/kconfigs/rpm.py @@ -12,12 +12,11 @@ from itertools import zip_longest from pathlib import Path from typing import Any -from typing import cast +from typing import NamedTuple from typing import TypeVar import aiosqlite from aiofiles.tempfile import TemporaryDirectory -from aiosqlite import Row from kconfigs.extractor import Extractor from kconfigs.fetcher import Checksum @@ -35,6 +34,14 @@ T = TypeVar("T", str, int) +class PkgMeta(NamedTuple): + version: str + release: str + href: str + checksum: str + checksum_type: str + + def samekindcmp(s1: T, s2: T) -> int: if s1 > s2: # s1 is greater, so it's newer @@ -107,7 +114,12 @@ async def __query_latest_db(self) -> None: yum_base, self.key, https_ok=True ) tree = ET.fromstring(data.decode("utf-8")) - primary_db_data = tree.findall(".//{*}data[@type='primary_db']")[0] + # prefer primary_db because it's sqlite, which is faster to query + primary_db_list = tree.findall(".//{*}data[@type='primary_db']") + if not primary_db_list: + # fall back to XML where necessary + primary_db_list = tree.findall(".//{*}data[@type='primary']") + primary_db_data = primary_db_list[0] location = primary_db_data.findall("{*}location")[0] checksum = primary_db_data.findall("{*}checksum")[0] href = location.attrib["href"] @@ -135,12 +147,8 @@ async def __fetch_latest_db(self) -> None: ) self.__latest_db_path = await maybe_decompress(file) - async def latest_version_url(self, pkg: str) -> tuple[str, Checksum | None]: - async with self.__mutex: - if not self.__latest_db_path: - await self.__fetch_latest_db() - assert self.__latest_db_path - + async def __packages_from_sqlite(self, pkg: str) -> list[PkgMeta]: + assert self.__latest_db_path async with aiosqlite.connect(self.__latest_db_path) as conn: result = await conn.execute( """ @@ -149,18 +157,56 @@ async def latest_version_url(self, pkg: str) -> tuple[str, Checksum | None]: """, (pkg,), ) - rows = list(await result.fetchall()) + rows = await result.fetchall() + return [PkgMeta(*row) for row in rows] + + async def __packages_from_xml(self, pkg: str) -> list[PkgMeta]: + assert self.__latest_db_path + with open(self.__latest_db_path, "rt") as f: + tree = ET.parse(f) + pkgs = tree.findall("{*}package[{*}name='%s']" % pkg) + res = [] + for pkg_elem in pkgs: + ver_elem = pkg_elem.find("{*}version") + csum_elem = pkg_elem.find("{*}checksum") + loc_elem = pkg_elem.find("{*}location") + assert ( + ver_elem is not None + and csum_elem is not None + and loc_elem is not None + ) + res.append( + PkgMeta( + ver_elem.attrib["ver"], + ver_elem.attrib["rel"], + loc_elem.attrib["href"], + csum_elem.text or "", # satisfy mypy here :/ + csum_elem.attrib["type"], + ) + ) + return res + + async def latest_version_url(self, pkg: str) -> tuple[str, Checksum | None]: + async with self.__mutex: + if not self.__latest_db_path: + await self.__fetch_latest_db() + assert self.__latest_db_path + + if self.__latest_db_path.suffix == ".xml": + rows = await self.__packages_from_xml(pkg) + else: + rows = await self.__packages_from_sqlite(pkg) - def cmp(t1: Row, t2: Row) -> int: - val = rpmvercmp(t1[0], t2[0]) + def cmp(t1: PkgMeta, t2: PkgMeta) -> int: + val = rpmvercmp(t1.version, t2.version) if val == 0: - val = rpmvercmp(t1[1], t2[1]) + val = rpmvercmp(t1.release, t2.release) return val rows.sort(key=cmp_to_key(cmp)) - href = cast(str, rows[-1][2]) - csum = cast(str, rows[-1][3]) - csum_type = cast(str, rows[-1][4]) + href = rows[-1].href + csum = rows[-1].checksum + csum_type = rows[-1].checksum_type if not href.startswith("http:") or href.startswith("https:"): href = posixpath.join(self.index, href) return (href, (csum_type, csum)) @@ -193,12 +239,29 @@ async def extract_rpm_file( shutil.copyfile(tdpath / file, output) +# Some GPG "key" names in the "gpg-keys" directory are actually a combination of +# multiple keys into a GPG database. This works for the gpg_verify() function, +# which will happily accept that database and verify using any one of the given +# keys. However, for RPM signature verification, we need to let RPM manage the +# GPG database. This dictionary maps GPG key database names to the underlying +# keys, so we can put them into a temporary RPM key database. +# TODO: generate this from the gpg-keys/Makefile directory? +MULTI_KEYS: dict[str, list[str]] = { + "asahi.gpg": ["fedora-asahi", "fedora-asahi-kernel"], +} + + async def verify_rpm(rpm: Path, key: str) -> None: - key_path = Path(__file__).parent.parent.resolve() / f"gpg-keys/{key}" + keydir = Path(__file__).parent.parent.resolve() / "gpg-keys" + if key in MULTI_KEYS: + key_paths = [keydir / s for s in MULTI_KEYS[key]] + else: + key_paths = [keydir / key] async with TemporaryDirectory() as td: - await check_call( - ["/usr/bin/rpm", f"--dbpath={td}", "--import", key_path] - ) + for key_path in key_paths: + await check_call( + ["/usr/bin/rpm", f"--dbpath={td}", "--import", key_path] + ) proc = await asyncio.create_subprocess_exec( "/usr/bin/rpm", f"--dbpath={td}", diff --git a/kconfigs/util.py b/kconfigs/util.py index 16a0927..b90d6db 100644 --- a/kconfigs/util.py +++ b/kconfigs/util.py @@ -23,6 +23,7 @@ "yum.oracle.com", "source.android.com", "dl.fedoraproject.org", + "download.copr.fedorainfracloud.org", }