diff --git a/src/cli.rs b/src/cli.rs index 9176337..b855043 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -102,8 +102,9 @@ pub enum Commands { List, /// Create a detached minisign signature for a .zst file Sign { - /// Path to the .zst file to sign - file: PathBuf, + /// One or more .zst files to sign + #[arg(value_name = "FILE", required = true, num_args = 1..)] + files: Vec, }, /// Repository management Repo { diff --git a/src/commands.rs b/src/commands.rs index b50f704..e4023be 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1591,12 +1591,14 @@ pub fn run(cli: Cli) -> Result<()> { let db_path = config.db_dir.join("packages.db"); db::list_packages(&db_path)?; } - Commands::Sign { file } => { - let sig_path = signing::sign_zst_file_detached(&cli.rootfs, &file)?; - ui::success(format!( - "Created detached signature: {}", - sig_path.display() - )); + Commands::Sign { files } => { + let sig_paths = signing::sign_zst_files_detached(&cli.rootfs, &files)?; + for sig_path in sig_paths { + ui::success(format!( + "Created detached signature: {}", + sig_path.display() + )); + } } Commands::Repo { command } => match command { RepoCommands::Create { dir } => { diff --git a/src/signing.rs b/src/signing.rs index 59e67c1..b70ae99 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -1,7 +1,7 @@ //! Minisign-based detached signature helpers. use anyhow::{Context, Result}; -use minisign::{PublicKey, SecretKeyBox, SignatureBox}; +use minisign::{PublicKey, SecretKey, SecretKeyBox, SignatureBox}; use std::fs; use std::path::{Path, PathBuf}; @@ -155,17 +155,12 @@ fn detached_sig_path(input: &Path) -> PathBuf { PathBuf::from(format!("{}.sig", input.display())) } -fn sign_detached_with_key_paths(input: &Path, sig_path: &Path, keys: &KeyLocations) -> Result<()> { - if !input.exists() { - anyhow::bail!("File not found: {}", input.display()); - } - if !is_zst_file(input) { - anyhow::bail!( - "Signing command currently only supports .zst files: {}", - input.display() - ); - } +struct SigningMaterial { + secret_key: SecretKey, + public_key: Option, +} +fn load_signing_material(keys: &KeyLocations) -> Result { let signing_key_path = keys.signing_key.as_ref().with_context( || "No minisign signing key found in /usr/share/depot/keys/sign (checked rootfs and host)", )?; @@ -204,11 +199,32 @@ fn sign_detached_with_key_paths(input: &Path, sig_path: &Path, keys: &KeyLocatio None }; + Ok(SigningMaterial { + secret_key, + public_key, + }) +} + +fn sign_detached_with_material( + input: &Path, + sig_path: &Path, + signing_material: &SigningMaterial, +) -> Result<()> { + if !input.exists() { + anyhow::bail!("File not found: {}", input.display()); + } + if !is_zst_file(input) { + anyhow::bail!( + "Signing command currently only supports .zst files: {}", + input.display() + ); + } + let file = fs::File::open(input).with_context(|| format!("Failed to open {}", input.display()))?; let sig = minisign::sign( - public_key.as_ref(), - &secret_key, + signing_material.public_key.as_ref(), + &signing_material.secret_key, file, None, Some(&format!("depot signature for {}", input.display())), @@ -273,12 +289,23 @@ pub fn verify_zst_file_detached_with_public_key( verify_detached_with_key_paths(input, sig_path, &keys) } -/// Sign a `.zst` file with a detached minisign signature written to `.sig`. -pub fn sign_zst_file_detached(rootfs: &Path, input: &Path) -> Result { +/// Sign one or more `.zst` files with detached minisign signatures written to `.sig`. +pub fn sign_zst_files_detached(rootfs: &Path, inputs: &[PathBuf]) -> Result> { + if inputs.is_empty() { + anyhow::bail!("No input files provided for signing"); + } + let keys = locate_keys(rootfs)?; - let sig_path = detached_sig_path(input); - sign_detached_with_key_paths(input, &sig_path, &keys)?; - Ok(sig_path) + let signing_material = load_signing_material(&keys)?; + let mut sig_paths = Vec::with_capacity(inputs.len()); + + for input in inputs { + let sig_path = detached_sig_path(input); + sign_detached_with_material(input, &sig_path, &signing_material)?; + sig_paths.push(sig_path); + } + + Ok(sig_paths) } /// Attempt to sign a `.zst` file using discovered keys; skip if no signing key exists. @@ -294,8 +321,9 @@ pub fn auto_sign_zst_file_detached(rootfs: &Path, input: &Path) -> Result