apt: move the keyserver lookup URL to data/keyserver.yml

This commit is contained in:
2026-09-18 13:28:05 +02:00
parent 7af767898e
commit 7601524b7c
4 changed files with 53 additions and 7 deletions
+17
View File
@@ -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<fingerprint> 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}"
+32 -4
View File
@@ -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());
+1 -1
View File
@@ -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}"))?;
+3 -2
View File
@@ -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