use zeroize::Zeroizing;
use crate::config::{FederationPeerSettings, FederationSettings};
use crate::error::{Result, VaultError};
pub const SEAL_PASSPHRASE_ENV: &str = "aimodelvault_FEDERATION_PASSPHRASE";
pub const API_KEY_HEADER: &str = "X-API-Key";
pub const VAULT_PASSPHRASE_ENV: &str = "aimodelvault_PASSPHRASE";
pub const ORIGIN_CHECKPOINT_KEY: &str = "federation_origin_checkpoint_id";
#[must_use]
pub fn federation_checkpoint_id(version: &crate::version::ModelVersion) -> String {
version
.metadata
.get(ORIGIN_CHECKPOINT_KEY)
.cloned()
.unwrap_or_else(|| version.checkpoint_id.clone())
}
#[must_use]
pub fn origin_metadata(origin_id: &str) -> std::collections::HashMap<String, String> {
let mut fields = std::collections::HashMap::new();
fields.insert(ORIGIN_CHECKPOINT_KEY.to_string(), origin_id.to_string());
fields
}
pub fn startup_passphrase() -> Result<Option<Zeroizing<String>>> {
let Ok(value) = std::env::var(VAULT_PASSPHRASE_ENV) else {
return Ok(None);
};
if value.trim().is_empty() {
return Ok(None);
}
crate::kms::resolve(&value).map(Some)
}
pub fn resolve_peer_key(peer: &FederationPeerSettings) -> Result<Option<Zeroizing<String>>> {
match &peer.api_key {
Some(raw) => Ok(Some(crate::kms::resolve(raw)?)),
None => Ok(None),
}
}
pub fn accepted_keys(settings: &FederationSettings) -> Result<Vec<Zeroizing<String>>> {
let mut keys = Vec::new();
for peer in settings.peers.iter().filter(|p| p.enabled) {
if let Some(key) = resolve_peer_key(peer)? {
if !key.is_empty() {
keys.push(key);
}
}
}
Ok(keys)
}
pub fn to_manager_config(
settings: &FederationSettings,
) -> Result<crate::federation::FederationConfig> {
let mut peers = Vec::with_capacity(settings.peers.len());
for peer in &settings.peers {
let key = resolve_peer_key(peer)?;
peers.push(crate::federation::PeerConfig {
node_id: peer.node_id.clone(),
name: peer.name.clone(),
endpoint: peer.endpoint.trim_end_matches('/').to_string(),
api_key: key.map(|k| k.to_string()),
enabled: peer.enabled,
});
}
let defaults = crate::federation::FederationConfig::default();
let node_id = if settings.node_id.trim().is_empty() {
eprintln!(
"warning: federation.node_id is unset — using a random id for this process. \
Vector clocks are keyed by node id, so sync history will not carry across \
restarts. Set federation.node_id to a stable value."
);
defaults.node_id
} else {
settings.node_id.clone()
};
let node_name = if settings.node_name.trim().is_empty() {
defaults.node_name
} else {
settings.node_name.clone()
};
Ok(crate::federation::FederationConfig {
node_id,
node_name,
peers,
..crate::federation::FederationConfig::default()
})
}
#[must_use]
pub fn secret_eq(a: &[u8], b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
let mut diff = 0u8;
for (x, y) in a.iter().zip(b.iter()) {
diff |= x ^ y;
}
diff == 0
}
#[must_use]
pub fn key_is_accepted(presented: &str, accepted: &[Zeroizing<String>]) -> bool {
let mut matched = false;
for key in accepted {
matched |= secret_eq(presented.as_bytes(), key.as_bytes());
}
matched
}
pub fn seal_passphrase() -> Result<Zeroizing<String>> {
let value = std::env::var(SEAL_PASSPHRASE_ENV).map_err(|_| {
VaultError::ConfigError(format!(
"federation.seal_transfers is on but ${SEAL_PASSPHRASE_ENV} is not set. \
Both peers must share the same value. Set it, or set \
federation.seal_transfers = false to send models unencrypted \
(only defensible on a network you fully control)."
))
})?;
if value.trim().is_empty() {
return Err(VaultError::ConfigError(format!(
"${SEAL_PASSPHRASE_ENV} is set but empty"
)));
}
Ok(Zeroizing::new(value))
}
pub fn seal_for_transit(settings: &FederationSettings, plaintext: &[u8]) -> Result<Vec<u8>> {
if !settings.seal_transfers {
return Ok(plaintext.to_vec());
}
let passphrase = seal_passphrase()?;
crate::cloud_envelope::seal(plaintext, passphrase.as_bytes().to_vec())
}
pub fn open_from_transit(settings: &FederationSettings, received: Vec<u8>) -> Result<Vec<u8>> {
let sealed = crate::cloud_envelope::is_sealed(&received);
if sealed {
let passphrase = seal_passphrase()?;
return crate::cloud_envelope::open(&received, passphrase.as_bytes().to_vec());
}
if settings.seal_transfers {
return Err(VaultError::ConfigError(
"peer sent an unsealed model while federation.seal_transfers is on. \
Either the peer has sealing disabled or the transfer was downgraded; \
refusing it rather than storing an unverified plaintext model."
.to_string(),
));
}
Ok(received)
}
#[cfg(test)]
mod tests {
use super::*;
fn peer(key: Option<&str>, enabled: bool) -> FederationPeerSettings {
FederationPeerSettings {
node_id: "peer-1".into(),
name: "peer".into(),
endpoint: "https://peer.example.com".into(),
api_key: key.map(str::to_string),
enabled,
}
}
fn version_with(checkpoint_id: &str, origin: Option<&str>) -> crate::version::ModelVersion {
let mut metadata = std::collections::HashMap::new();
if let Some(origin) = origin {
metadata.insert(ORIGIN_CHECKPOINT_KEY.to_string(), origin.to_string());
}
crate::version::ModelVersion {
version: 1,
checkpoint_id: checkpoint_id.to_string(),
timestamp: chrono::Utc::now(),
parent_version: None,
format: "safetensors".into(),
size_bytes: 1,
compressed_size_bytes: 1,
checksum_sha256: "abc".into(),
metadata,
file_path: "f".into(),
}
}
#[test]
fn a_received_version_advertises_its_origin_id() {
let local_only = version_with("local-abc", None);
assert_eq!(federation_checkpoint_id(&local_only), "local-abc");
let received = version_with("local-xyz", Some("origin-1"));
assert_eq!(
federation_checkpoint_id(&received),
"origin-1",
"a received version must advertise the id it arrived with, not the \
one this vault minted for it"
);
let fields = origin_metadata("origin-1");
assert_eq!(fields.get(ORIGIN_CHECKPOINT_KEY).unwrap(), "origin-1");
}
#[test]
fn secret_eq_matches_only_identical_values() {
assert!(secret_eq(b"abc", b"abc"));
assert!(!secret_eq(b"abc", b"abd"));
assert!(!secret_eq(b"abc", b"ab"));
assert!(secret_eq(b"", b""));
}
#[test]
fn disabled_peers_do_not_grant_access() {
let settings = FederationSettings {
peers: vec![peer(Some("literal-key"), false)],
..Default::default()
};
let keys = accepted_keys(&settings).unwrap();
assert!(keys.is_empty());
assert!(!key_is_accepted("literal-key", &keys));
}
#[test]
fn enabled_peer_key_is_accepted() {
let settings = FederationSettings {
peers: vec![peer(Some("literal-key"), true)],
..Default::default()
};
let keys = accepted_keys(&settings).unwrap();
assert!(key_is_accepted("literal-key", &keys));
assert!(!key_is_accepted("wrong-key", &keys));
assert!(!key_is_accepted("", &keys));
}
#[test]
fn peer_without_a_key_contributes_nothing() {
let settings = FederationSettings {
peers: vec![peer(None, true)],
..Default::default()
};
assert!(accepted_keys(&settings).unwrap().is_empty());
}
#[test]
fn sealing_defaults_to_on() {
assert!(FederationSettings::default().seal_transfers);
}
#[test]
fn unsealed_arrival_is_refused_when_sealing_is_on() {
let settings = FederationSettings::default();
assert!(settings.seal_transfers);
let err = open_from_transit(&settings, b"raw model bytes".to_vec()).unwrap_err();
assert!(
err.to_string().contains("unsealed"),
"expected a downgrade complaint, got: {err}"
);
}
#[test]
fn unsealed_arrival_passes_through_when_sealing_is_off() {
let settings = FederationSettings {
seal_transfers: false,
..Default::default()
};
let data = open_from_transit(&settings, b"raw model bytes".to_vec()).unwrap();
assert_eq!(data, b"raw model bytes");
}
#[test]
fn seal_roundtrip_hides_the_plaintext() {
std::env::set_var(SEAL_PASSPHRASE_ENV, "shared-federation-passphrase");
let settings = FederationSettings::default();
let plaintext = b"weights-that-should-not-appear-on-the-wire";
let sealed = seal_for_transit(&settings, plaintext).unwrap();
assert!(crate::cloud_envelope::is_sealed(&sealed));
assert!(
!sealed
.windows(plaintext.len())
.any(|w| w == plaintext.as_slice()),
"plaintext must not survive in the sealed bytes"
);
let opened = open_from_transit(&settings, sealed).unwrap();
assert_eq!(opened, plaintext);
std::env::remove_var(SEAL_PASSPHRASE_ENV);
}
}