git.delta.rocks / jrsonnet / refs/commits / 5b343db89280

difftreelog

source

crates/fleet-base/src/secret.rs3.8 KiBsourcehistory
1use std::collections::BTreeSet;23use anyhow::Result;4use chrono::{DateTime, Utc};5use nix_eval::{Value, nix_go, nix_go_json};67use crate::fleetdata::FleetSecretData;89#[derive(Debug)]10pub struct Expectations {11	pub owners: BTreeSet<String>,12	pub generation_data: serde_json::Value,13	pub public_parts: BTreeSet<String>,14	pub private_parts: BTreeSet<String>,15}1617pub struct HostSecretDefinition(pub(crate) String, pub(crate) Value);18impl HostSecretDefinition {19	pub fn is_managed(&self) -> Result<bool> {20		let value = &self.1;21		Ok(!nix_go!(value.generator).is_null())22	}23	pub fn expectations(&self) -> Result<Expectations> {24		let value = &self.1;25		Ok(Expectations {26			owners: BTreeSet::from([self.0.clone()]),27			generation_data: nix_go_json!(value.expectedGenerationData),28			public_parts: nix_go_json!(value.expectedPublicParts),29			private_parts: nix_go_json!(value.expectedPrivateParts),30		})31	}32	pub fn inner(&self) -> Value {33		self.1.clone()34	}35}3637pub struct SharedSecretDefinition(pub(crate) Value);38impl SharedSecretDefinition {39	pub fn is_managed(&self) -> Result<bool> {40		let value = &self.0;41		Ok(!nix_go!(value.generator).is_null())42	}43	pub fn expectations(&self) -> Result<Expectations> {44		let value = &self.0;45		Ok(Expectations {46			owners: nix_go_json!(value.expectedOwners),47			generation_data: nix_go_json!(value.expectedGenerationData),48			public_parts: nix_go_json!(value.expectedPublicParts),49			private_parts: nix_go_json!(value.expectedPrivateParts),50		})51	}52	pub fn inner(&self) -> Value {53		self.0.clone()54	}55}5657#[derive(thiserror::Error, Debug)]58pub enum RegenerationReason {59	#[error("owners added: {0:?}")]60	OwnersAdded(BTreeSet<String>),61	#[error("owners added: {0:?}")]62	OwnersRemoved(BTreeSet<String>),63	#[error("unexpected generation data, expected: {expected:?}, found: {found:?}")]64	GenerationData {65		expected: serde_json::Value,66		found: serde_json::Value,67	},68	#[error("unexpected part list, expected: {expected:?}, found: {found:?}")]69	PartList {70		expected: BTreeSet<String>,71		found: BTreeSet<String>,72	},73	#[error("part {0} is expected to be encrypted")]74	ExpectedPrivate(String),75	#[error("part {0} is not expected to be encrypted")]76	ExpectedPublic(String),77	#[error("secret is expired at {0}")]78	Expired(DateTime<Utc>),79}8081pub fn secret_needs_regeneration(82	secret: &FleetSecretData,83	owners: &BTreeSet<String>,84	expectations: &Expectations,85) -> Option<RegenerationReason> {86	if !owners.is_empty() {87		let added: BTreeSet<String> = expectations.owners.difference(owners).cloned().collect();88		if !added.is_empty() {89			return Some(RegenerationReason::OwnersAdded(added));90		}9192		let removed: BTreeSet<String> = owners.difference(&expectations.owners).cloned().collect();93		if !removed.is_empty() {94			return Some(RegenerationReason::OwnersRemoved(removed));95		}96	}9798	if secret.generation_data != expectations.generation_data {99		return Some(RegenerationReason::GenerationData {100			expected: expectations.generation_data.clone(),101			found: secret.generation_data.clone(),102		});103	}104105	if !expectations.public_parts.is_empty() || !expectations.private_parts.is_empty() {106		let expected: BTreeSet<String> = expectations107			.public_parts108			.union(&expectations.private_parts)109			.cloned()110			.collect();111		let found: BTreeSet<String> = secret.parts.keys().cloned().collect();112113		if found != expected {114			return Some(RegenerationReason::PartList { expected, found });115		}116117		for (name, value) in secret.parts.iter() {118			if value.raw.encrypted {119				if !expectations.private_parts.contains(name) {120					return Some(RegenerationReason::ExpectedPrivate(name.clone()));121				}122			} else if !expectations.public_parts.contains(name) {123				return Some(RegenerationReason::ExpectedPublic(name.clone()));124			}125		}126	}127128	if let Some(expiration) = secret.expires_at {129		// TODO: Leeway?130		if expiration < Utc::now() {131			return Some(RegenerationReason::Expired(expiration));132		}133	}134135	None136}