From 7601524b7c89e01861f80c418879c6b599904172 Mon Sep 17 00:00:00 2001 From: Valentin Haudiquet Date: Fri, 18 Sep 2026 13:28:05 +0200 Subject: [PATCH] apt: move the keyserver lookup URL to data/keyserver.yml --- data/keyserver.yml | 17 +++++++++++++++++ src/apt/keyring.rs | 36 ++++++++++++++++++++++++++++++++---- src/apt/release.rs | 2 +- src/data.rs | 5 +++-- 4 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 data/keyserver.yml diff --git a/data/keyserver.yml b/data/keyserver.yml new file mode 100644 index 0000000..4c1091b --- /dev/null +++ b/data/keyserver.yml @@ -0,0 +1,17 @@ +## Keyserver lookup endpoint used to fetch PPA signing keys. +## Like host_keys.yml, this file exists so that a static endpoint is data, +## updatable in one reviewable place, instead of hardcoded in the source — +## the URL was previously duplicated in the apt keyring and release +## modules. Sparse on purpose: it grows if keyserver pools or alternates +## ever need to be tried. +## +## The template carries its variable part as a {fingerprint} placeholder, +## substituted by the accessor of src/apt/keyring.rs with plain string +## replacement. +## +## Where the value comes from: keyserver.ubuntu.com, Ubuntu's OpenPKS +## (formerly SKS) keyserver; op=get with search=0x is the +## documented machine interface fetching one key by fingerprint +## (https://keyserver.ubuntu.com). + +lookup_template: "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x{fingerprint}" diff --git a/src/apt/keyring.rs b/src/apt/keyring.rs index c6cfa1f..f6357f5 100644 --- a/src/apt/keyring.rs +++ b/src/apt/keyring.rs @@ -4,6 +4,7 @@ //! for mmdebstrap operations and for PPA packages by downloading them. use crate::context; +use crate::data::embed_data; use crate::distro_info; use serde::Deserialize; use std::error::Error; @@ -11,6 +12,26 @@ use std::os::unix::fs::MetadataExt; use std::path::{Path, PathBuf}; use std::sync::Arc; +/// Keyserver endpoint, loaded from the bundled `keyserver.yml` data file +/// (same pattern as `distro_info.yml`): the lookup URL is a static +/// endpoint that was previously hardcoded in two modules. +#[derive(Debug, Deserialize)] +struct KeyserverData { + /// OpenPGP key lookup URL template (`{fingerprint}`) + lookup_template: String, +} + +embed_data! { + static ref KEYSERVER_DATA: KeyserverData = "../../data/keyserver.yml" +} + +/// URL fetching the OpenPGP key of `fingerprint` from the keyserver +pub(crate) fn keyserver_lookup_url(fingerprint: &str) -> String { + KEYSERVER_DATA + .lookup_template + .replace("{fingerprint}", fingerprint) +} + /// Launchpad API response structure for PPA information #[derive(Deserialize)] struct LaunchpadPpaResponse { @@ -276,10 +297,7 @@ pub async fn download_trust_ppa_key( log::debug!("Found PPA signing key fingerprint: {}", fingerprint); // Download the actual key from the keyserver using the fingerprint - let keyserver_url = format!( - "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x{}", - fingerprint - ); + let keyserver_url = keyserver_lookup_url(&fingerprint); log::debug!("Downloading key from keyserver: {}", keyserver_url); let mut curl_cmd = ctx.command("curl"); @@ -314,6 +332,16 @@ pub async fn download_trust_ppa_key( mod tests { use super::*; + /// The data-driven template renders the lookup URL the hardcoded + /// format! used to build (verified against the live keyserver) + #[test] + fn keyserver_lookup_url_substitutes_the_fingerprint() { + assert_eq!( + keyserver_lookup_url("0123456789ABCDEF"), + "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x0123456789ABCDEF" + ); + } + #[test] fn test_validate_keyring_dir_accepts_private_dir_owned_by_current_user() { assert!(validate_keyring_dir(1000, 0o700, 1000).is_ok()); diff --git a/src/apt/release.rs b/src/apt/release.rs index 8f53b63..412c695 100644 --- a/src/apt/release.rs +++ b/src/apt/release.rs @@ -905,7 +905,7 @@ pub async fn ppa_keyring_bytes( .into()); } - let key_url = format!("https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x{fingerprint}"); + let key_url = crate::apt::keyring::keyserver_lookup_url(&fingerprint); let armored = fetch_keyring_cached(&key_url).await?; let keyring = dearmor(&armored) .map_err(|e| format!("invalid PGP armor in the key of PPA '{owner}/{name}': {e}"))?; diff --git a/src/data.rs b/src/data.rs index 4d31c02..0b561ba 100644 --- a/src/data.rs +++ b/src/data.rs @@ -7,8 +7,9 @@ //! //! This module is deliberately not a central registry: each file is //! embedded by the module that owns it (distro_info.rs owns -//! data/distro_info.yml, launchpad.rs owns data/launchpad.yml, put/ssh.rs -//! owns data/host_keys.yml, quirks.rs owns data/quirks.yml) through the +//! data/distro_info.yml, launchpad.rs owns data/launchpad.yml, +//! apt/keyring.rs owns data/keyserver.yml, put/ssh.rs owns +//! data/host_keys.yml, quirks.rs owns data/quirks.yml) through the //! [`embed_data!`] macro below, so data //! and its accessors stay together and a diff touching one domain cannot //! half-touch another. The macro embeds the file at compile time and