deb: make sure to have the right apt keyrings
Some checks failed
CI / build (push) Failing after 14s
Some checks failed
CI / build (push) Failing after 14s
This commit is contained in:
@@ -10,6 +10,7 @@ dist_info:
|
||||
dist:
|
||||
debian:
|
||||
base_url: http://deb.debian.org/debian
|
||||
archive_keyring: https://ftp-master.debian.org/keys/archive-key-{series_num}.asc
|
||||
pockets:
|
||||
- proposed-updates
|
||||
- updates
|
||||
@@ -18,9 +19,10 @@ dist:
|
||||
network: https://salsa.debian.org/debian/distro-info-data/-/raw/main/debian.csv
|
||||
ubuntu:
|
||||
base_url: http://archive.ubuntu.com/ubuntu
|
||||
archive_keyring: http://archive.ubuntu.com/ubuntu/project/ubuntu-archive-keyring.gpg
|
||||
pockets:
|
||||
- proposed
|
||||
- updates
|
||||
series:
|
||||
local: /usr/share/distro-info/ubuntu.csv
|
||||
network: https://salsa.debian.org/debian/distro-info-data/-/raw/main/ubuntu.csv
|
||||
network: https://salsa.debian.org/debian/distro-info-data/-/raw/main/ubuntu.csv
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
//! APT keyring management for mmdebstrap
|
||||
//!
|
||||
//! Provides a simple function to ensure that archive keyrings are available
|
||||
//! for mmdebstrap operations by downloading them from specified URLs.
|
||||
|
||||
use crate::context;
|
||||
use crate::distro_info;
|
||||
use std::error::Error;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Download a keyring into apt trusted.gpg.d directory, trusting that keyring
|
||||
pub async fn download_trust_keyring(
|
||||
ctx: Option<Arc<context::Context>>,
|
||||
series: &str,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let ctx = ctx.unwrap_or_else(context::current);
|
||||
|
||||
// Obtain keyring URL from distro_info
|
||||
let keyring_url = distro_info::get_keyring_url(series).await?;
|
||||
log::debug!("Downloading keyring from: {}", keyring_url);
|
||||
|
||||
// Create trusted.gpg.d directory if it doesn't exist
|
||||
let trusted_gpg_d = "/etc/apt/trusted.gpg.d";
|
||||
if !ctx.exists(Path::new(trusted_gpg_d))? {
|
||||
ctx.command("mkdir").arg("-p").arg(trusted_gpg_d).status()?;
|
||||
}
|
||||
|
||||
// Generate a filename for the keyring
|
||||
let filename = format!("pkh-{}.gpg", series);
|
||||
let keyring_path = format!("{}/{}", trusted_gpg_d, filename);
|
||||
|
||||
// Download the keyring directly to the final location using curl
|
||||
let mut curl_cmd = ctx.command("curl");
|
||||
curl_cmd
|
||||
.arg("-s")
|
||||
.arg("-f")
|
||||
.arg("-L")
|
||||
.arg(&keyring_url)
|
||||
.arg("--output")
|
||||
.arg(&keyring_path);
|
||||
|
||||
let status = curl_cmd.status()?;
|
||||
if !status.success() {
|
||||
return Err(format!("Failed to download keyring from {}", keyring_url).into());
|
||||
}
|
||||
|
||||
log::info!(
|
||||
"Successfully downloaded and installed keyring for {} to {}",
|
||||
series,
|
||||
keyring_path
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
pub mod keyring;
|
||||
pub mod sources;
|
||||
|
||||
@@ -120,6 +120,11 @@ impl EphemeralContextGuard {
|
||||
.arg(lockfile_path.to_string_lossy().to_string())
|
||||
.status()?;
|
||||
|
||||
// Make sure we have the right apt keyrings to mmdebstrap the chroot
|
||||
tokio::runtime::Runtime::new().unwrap().block_on(
|
||||
crate::apt::keyring::download_trust_keyring(Some(ctx.clone()), series),
|
||||
)?;
|
||||
|
||||
// Use mmdebstrap to download the tarball to the cache directory
|
||||
let status = ctx
|
||||
.command("mmdebstrap")
|
||||
|
||||
@@ -13,6 +13,7 @@ struct SeriesInfo {
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct DistData {
|
||||
base_url: String,
|
||||
archive_keyring: String,
|
||||
pockets: Vec<String>,
|
||||
series: SeriesInfo,
|
||||
}
|
||||
@@ -124,6 +125,27 @@ pub fn get_base_url(dist: &str) -> String {
|
||||
DATA.dist.get(dist).unwrap().base_url.clone()
|
||||
}
|
||||
|
||||
/// Obtain the URL for the archive keyring of a distribution series
|
||||
pub async fn get_keyring_url(series: &str) -> Result<String, Box<dyn Error>> {
|
||||
let dist = get_dist_from_series(series).await?;
|
||||
let dist_data = DATA
|
||||
.dist
|
||||
.get(&dist)
|
||||
.ok_or(format!("Unsupported distribution: {}", dist))?;
|
||||
|
||||
// For Debian, we need the series number to form the keyring URL
|
||||
if dist == "debian" {
|
||||
let series_num = get_debian_series_number(series).await?.unwrap();
|
||||
// Replace {series_num} placeholder with the actual series number
|
||||
Ok(dist_data
|
||||
.archive_keyring
|
||||
.replace("{series_num}", &series_num))
|
||||
} else {
|
||||
// For other distributions like Ubuntu, use the keyring directly
|
||||
Ok(dist_data.archive_keyring.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain the URL for the 'Release' file of a distribution series
|
||||
fn get_release_url(base_url: &str, series: &str, pocket: &str) -> String {
|
||||
let pocket_full = if pocket.is_empty() {
|
||||
@@ -159,6 +181,44 @@ pub async fn get_components(
|
||||
Err("Components not found.".into())
|
||||
}
|
||||
|
||||
/// Map a Debian series name to its version number
|
||||
pub async fn get_debian_series_number(series: &str) -> Result<Option<String>, Box<dyn Error>> {
|
||||
let series_info = &DATA.dist.get("debian").unwrap().series;
|
||||
let content = if Path::new(series_info.local.as_str()).exists() {
|
||||
std::fs::read_to_string(series_info.local.as_str())?
|
||||
} else {
|
||||
reqwest::get(series_info.network.as_str())
|
||||
.await?
|
||||
.text()
|
||||
.await?
|
||||
};
|
||||
|
||||
let mut rdr = csv::ReaderBuilder::new()
|
||||
.flexible(true)
|
||||
.from_reader(content.as_bytes());
|
||||
|
||||
let headers = rdr.headers()?.clone();
|
||||
let series_idx = headers
|
||||
.iter()
|
||||
.position(|h| h == "series")
|
||||
.ok_or("Column 'series' not found")?;
|
||||
let version_idx = headers
|
||||
.iter()
|
||||
.position(|h| h == "version")
|
||||
.ok_or("Column 'version' not found")?;
|
||||
|
||||
for result in rdr.records() {
|
||||
let record = result?;
|
||||
if let (Some(s), Some(v)) = (record.get(series_idx), record.get(version_idx))
|
||||
&& s.to_lowercase() == series.to_lowercase()
|
||||
{
|
||||
return Ok(Some(v.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -182,4 +242,20 @@ mod tests {
|
||||
assert_eq!(get_dist_from_series("sid").await.unwrap(), "debian");
|
||||
assert_eq!(get_dist_from_series("noble").await.unwrap(), "ubuntu");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_debian_series_number() {
|
||||
// Test with known Debian series
|
||||
let bookworm_number = get_debian_series_number("bookworm").await.unwrap();
|
||||
assert!(bookworm_number.is_some());
|
||||
assert_eq!(bookworm_number.unwrap(), "12");
|
||||
|
||||
let trixie_number = get_debian_series_number("trixie").await.unwrap();
|
||||
assert!(trixie_number.is_some());
|
||||
assert_eq!(trixie_number.unwrap(), "13");
|
||||
|
||||
// Test with unknown series
|
||||
let unknown_number = get_debian_series_number("unknown").await.unwrap();
|
||||
assert!(unknown_number.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user