Add signature handling for manifests

- Implemented support for fetching, importing, and storing signature payloads during transaction creation.
- Added the `Signature` struct to represent signature-related action data.
- Updated `Manifest` to include and process `signatures` as part of its fields.
- Enabled signature file imports with proper path resolution in `pkg6repo`.
This commit is contained in:
Till Wegmueller 2026-02-05 22:26:53 +01:00
parent 38baf16b6f
commit dfc24725b8
No known key found for this signature in database
3 changed files with 91 additions and 1 deletions

View file

@ -790,6 +790,35 @@ impl From<Action> for Transform {
} }
} }
#[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize, Diff)]
#[diff(attr(
#[derive(Debug, PartialEq)]
))]
pub struct Signature {
pub value: String,
pub algorithm: String,
pub chain: String,
pub chash: String,
pub version: String,
}
impl From<Action> for Signature {
fn from(act: Action) -> Self {
let mut sig = Signature::default();
sig.value = act.payload_string;
for prop in act.properties {
match prop.key.as_str() {
"algorithm" => sig.algorithm = prop.value,
"chain" => sig.chain = prop.value,
"chash" => sig.chash = prop.value,
"version" => sig.version = prop.value,
_ => {}
}
}
sig
}
}
#[derive(Hash, Eq, PartialEq, Debug, Default, Clone, Deserialize, Serialize, Diff)] #[derive(Hash, Eq, PartialEq, Debug, Default, Clone, Deserialize, Serialize, Diff)]
#[diff(attr( #[diff(attr(
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -827,6 +856,8 @@ pub struct Manifest {
pub legacies: Vec<Legacy>, pub legacies: Vec<Legacy>,
#[serde(skip_serializing_if = "Vec::is_empty", default)] #[serde(skip_serializing_if = "Vec::is_empty", default)]
pub transforms: Vec<Transform>, pub transforms: Vec<Transform>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub signatures: Vec<Signature>,
} }
impl Manifest { impl Manifest {
@ -843,6 +874,7 @@ impl Manifest {
drivers: Vec::new(), drivers: Vec::new(),
legacies: Vec::new(), legacies: Vec::new(),
transforms: Vec::new(), transforms: Vec::new(),
signatures: Vec::new(),
} }
} }
@ -886,7 +918,7 @@ impl Manifest {
self.transforms.push(act.into()); self.transforms.push(act.into());
} }
ActionKind::Signature => { ActionKind::Signature => {
debug!("signature action encountered, skipping for now"); self.signatures.push(act.into());
} }
ActionKind::Unknown { action } => { ActionKind::Unknown { action } => {
debug!("action {:?} not known, skipping", action); debug!("action {:?} not known, skipping", action);

View file

@ -266,6 +266,23 @@ impl<'a, S: ReadableRepository + Sync> PackageReceiver<'a, S> {
txn.add_file((*file).clone(), &temp_file_path)?; txn.add_file((*file).clone(), &temp_file_path)?;
} }
// Fetch signature payloads
for sig in &manifest.signatures {
if sig.value.is_empty() {
continue;
}
let digest = &sig.value;
let temp_file_path = temp_dir.path().join(format!("sig-{}", digest));
debug!("Fetching signature payload {} to {}", digest, temp_file_path.display());
self.source.fetch_payload(publisher, digest, &temp_file_path)?;
let mut sig_file_action = crate::actions::File::default();
sig_file_action.path = format!("signature-{}", digest);
txn.add_file(sig_file_action, &temp_file_path)?;
}
txn.update_manifest(manifest.clone()); txn.update_manifest(manifest.clone());
txn.commit()?; txn.commit()?;

View file

@ -554,6 +554,47 @@ impl Pkg5Importer {
} }
} }
// Import signature files
for signature in &manifest.signatures {
if signature.value.is_empty() {
continue;
}
let hash = &signature.value;
// Determine the file path in the source repository
let first_two = &hash[0..2];
let next_two = &hash[2..4];
let file_path_new = file_dir.join(first_two).join(next_two).join(hash);
let file_path_old = file_dir.join(first_two).join(hash);
let file_path = if file_path_new.exists() {
file_path_new
} else if file_path_old.exists() {
file_path_old
} else {
warn!(
"Signature file not found in source repository: {}",
hash
);
continue;
};
// Use a unique name for the signature file in the proto dir
let proto_sig_path = proto_dir.join(format!("signature-{}", hash));
if let Some(parent) = proto_sig_path.parent() {
fs::create_dir_all(parent).map_err(|e| Pkg6RepoError::IoError(e))?;
}
fs::copy(&file_path, &proto_sig_path).map_err(|e| Pkg6RepoError::IoError(e))?;
// We need a FileAction to add it to the transaction
// Even though it's a signature, FileBackend uses add_file to store payloads
let mut sig_file_action = libips::actions::File::default();
sig_file_action.path = format!("signature-{}", hash);
// transaction.add_file will calculate the hash and store it in the repo's file dir
transaction.add_file(sig_file_action, &proto_sig_path)?;
}
// Update the manifest in the transaction // Update the manifest in the transaction
transaction.update_manifest(manifest); transaction.update_manifest(manifest);