use crate::experiment::{ExperimentError, SovereignArtifact, SovereignDistribution};
use crate::recipes::RecipeResult;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SovereignDeploymentConfig {
pub name: String,
pub version: String,
pub platforms: Vec<String>,
pub require_signatures: bool,
pub enable_nix_flake: bool,
pub offline_registry_path: Option<String>,
}
impl Default for SovereignDeploymentConfig {
fn default() -> Self {
Self {
name: "sovereign-model".to_string(),
version: "0.1.0".to_string(),
platforms: vec!["linux-x86_64".to_string()],
require_signatures: true,
enable_nix_flake: true,
offline_registry_path: None,
}
}
}
#[derive(Debug)]
pub struct SovereignDeploymentRecipe {
config: SovereignDeploymentConfig,
distribution: SovereignDistribution,
}
impl SovereignDeploymentRecipe {
pub fn new(config: SovereignDeploymentConfig) -> Self {
let mut distribution = SovereignDistribution::new(&config.name, &config.version);
for platform in &config.platforms {
distribution.add_platform(platform);
}
Self { config, distribution }
}
fn add_artifact_impl(
&mut self,
name: impl Into<String>,
sha256: impl Into<String>,
size_bytes: u64,
artifact_type: crate::experiment::ArtifactType,
) {
self.distribution.add_artifact(SovereignArtifact {
name: name.into(),
artifact_type,
sha256: sha256.into(),
size_bytes,
source_url: None,
});
}
pub fn add_model(
&mut self,
name: impl Into<String>,
sha256: impl Into<String>,
size_bytes: u64,
) {
self.add_artifact_impl(name, sha256, size_bytes, crate::experiment::ArtifactType::Model);
}
pub fn add_binary(
&mut self,
name: impl Into<String>,
sha256: impl Into<String>,
size_bytes: u64,
) {
self.add_artifact_impl(name, sha256, size_bytes, crate::experiment::ArtifactType::Binary);
}
pub fn add_dataset(
&mut self,
name: impl Into<String>,
sha256: impl Into<String>,
size_bytes: u64,
) {
self.add_artifact_impl(name, sha256, size_bytes, crate::experiment::ArtifactType::Dataset);
}
pub fn sign_artifact(&mut self, artifact_name: impl Into<String>, key_id: impl Into<String>) {
let name = artifact_name.into();
let signature = format!("sig_placeholder_{}", &name);
self.distribution.signatures.push(crate::experiment::ArtifactSignature {
artifact_name: name,
algorithm: crate::experiment::SignatureAlgorithm::Ed25519,
signature,
key_id: key_id.into(),
});
}
pub fn build(&self) -> Result<RecipeResult, ExperimentError> {
if self.config.require_signatures {
self.distribution.validate_signatures()?;
}
let mut result = RecipeResult::success("sovereign-deployment");
result = result.with_metric("artifact_count", self.distribution.artifacts.len() as f64);
result =
result.with_metric("total_size_bytes", self.distribution.total_size_bytes() as f64);
result = result.with_metric("platform_count", self.distribution.platforms.len() as f64);
for artifact in &self.distribution.artifacts {
result = result.with_artifact(&artifact.name);
}
Ok(result)
}
pub fn distribution(&self) -> &SovereignDistribution {
&self.distribution
}
pub fn export_manifest(&self) -> Result<String, ExperimentError> {
serde_json::to_string_pretty(&self.distribution)
.map_err(|e| ExperimentError::StorageError(e.to_string()))
}
}