use std::collections::HashMap;
use sha2::{Digest, Sha256};
use crate::error::ControlError;
#[derive(Debug, Clone)]
pub struct ResolvedArtifact {
pub component: Vec<u8>,
pub component_signature: Vec<u8>,
pub sbom: Vec<u8>,
pub sbom_signature: Vec<u8>,
}
pub trait ArtifactStore: Send + Sync {
fn resolve(&self, source: &str, pinned_digest: &str) -> Result<ResolvedArtifact, ControlError>;
}
pub(crate) fn sha256_pinned(bytes: &[u8]) -> String {
format!("sha256:{}", hex::encode(Sha256::digest(bytes)))
}
#[derive(Default)]
pub struct MemoryStore {
artifacts: HashMap<String, ResolvedArtifact>,
}
impl MemoryStore {
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, source: impl Into<String>, artifact: ResolvedArtifact) -> String {
let digest = sha256_pinned(&artifact.component);
self.artifacts.insert(source.into(), artifact);
digest
}
}
impl ArtifactStore for MemoryStore {
fn resolve(&self, source: &str, pinned_digest: &str) -> Result<ResolvedArtifact, ControlError> {
let artifact = self
.artifacts
.get(source)
.ok_or_else(|| ControlError::Artifact {
source_ref: source.to_string(),
reason: "not found in store".to_string(),
})?;
let actual = sha256_pinned(&artifact.component);
if actual != pinned_digest {
return Err(ControlError::DigestMismatch {
source_ref: source.to_string(),
expected: pinned_digest.to_string(),
actual,
});
}
Ok(artifact.clone())
}
}