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:
|
dist:
|
||||||
debian:
|
debian:
|
||||||
base_url: http://deb.debian.org/debian
|
base_url: http://deb.debian.org/debian
|
||||||
|
archive_keyring: https://ftp-master.debian.org/keys/archive-key-{series_num}.asc
|
||||||
pockets:
|
pockets:
|
||||||
- proposed-updates
|
- proposed-updates
|
||||||
- updates
|
- updates
|
||||||
@@ -18,9 +19,10 @@ dist:
|
|||||||
network: https://salsa.debian.org/debian/distro-info-data/-/raw/main/debian.csv
|
network: https://salsa.debian.org/debian/distro-info-data/-/raw/main/debian.csv
|
||||||
ubuntu:
|
ubuntu:
|
||||||
base_url: http://archive.ubuntu.com/ubuntu
|
base_url: http://archive.ubuntu.com/ubuntu
|
||||||
|
archive_keyring: http://archive.ubuntu.com/ubuntu/project/ubuntu-archive-keyring.gpg
|
||||||
pockets:
|
pockets:
|
||||||
- proposed
|
- proposed
|
||||||
- updates
|
- updates
|
||||||
series:
|
series:
|
||||||
local: /usr/share/distro-info/ubuntu.csv
|
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;
|
pub mod sources;
|
||||||
|
|||||||
@@ -120,6 +120,11 @@ impl EphemeralContextGuard {
|
|||||||
.arg(lockfile_path.to_string_lossy().to_string())
|
.arg(lockfile_path.to_string_lossy().to_string())
|
||||||
.status()?;
|
.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
|
// Use mmdebstrap to download the tarball to the cache directory
|
||||||
let status = ctx
|
let status = ctx
|
||||||
.command("mmdebstrap")
|
.command("mmdebstrap")
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ struct SeriesInfo {
|
|||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct DistData {
|
struct DistData {
|
||||||
base_url: String,
|
base_url: String,
|
||||||
|
archive_keyring: String,
|
||||||
pockets: Vec<String>,
|
pockets: Vec<String>,
|
||||||
series: SeriesInfo,
|
series: SeriesInfo,
|
||||||
}
|
}
|
||||||
@@ -124,6 +125,27 @@ pub fn get_base_url(dist: &str) -> String {
|
|||||||
DATA.dist.get(dist).unwrap().base_url.clone()
|
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
|
/// Obtain the URL for the 'Release' file of a distribution series
|
||||||
fn get_release_url(base_url: &str, series: &str, pocket: &str) -> String {
|
fn get_release_url(base_url: &str, series: &str, pocket: &str) -> String {
|
||||||
let pocket_full = if pocket.is_empty() {
|
let pocket_full = if pocket.is_empty() {
|
||||||
@@ -159,6 +181,44 @@ pub async fn get_components(
|
|||||||
Err("Components not found.".into())
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -182,4 +242,20 @@ mod tests {
|
|||||||
assert_eq!(get_dist_from_series("sid").await.unwrap(), "debian");
|
assert_eq!(get_dist_from_series("sid").await.unwrap(), "debian");
|
||||||
assert_eq!(get_dist_from_series("noble").await.unwrap(), "ubuntu");
|
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