use super::artifact::ObservedArtifactV1;
use super::plan::DeploymentIdentityV1;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct DeploymentInventoryV1 {
pub schema_version: u32,
pub inventory_id: String,
pub observed_at: String,
pub observed_identity: Option<DeploymentIdentityV1>,
pub observed_root: Option<DeploymentRootObservationV1>,
pub local_config: LocalDeploymentConfigV1,
pub observed_canisters: Vec<ObservedCanisterV1>,
pub observed_pool: Vec<ObservedPoolCanisterV1>,
pub observed_artifacts: Vec<ObservedArtifactV1>,
pub observed_verifier_readiness: VerifierReadinessObservationV1,
pub unresolved_observations: Vec<DeploymentObservationGapV1>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct DeploymentRootObservationV1 {
pub deployment_name: String,
pub network: String,
pub fleet_template: String,
pub root_principal: String,
pub observed_canister_id: String,
pub observation_source: DeploymentRootObservationSourceV1,
pub control_class: CanisterControlClassV1,
pub controllers: Vec<String>,
pub module_hash: Option<String>,
pub status: Option<String>,
pub role_assignment_source: Option<String>,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum DeploymentRootObservationSourceV1 {
IcpCanisterStatus,
LocalDeploymentState,
}
impl DeploymentRootObservationSourceV1 {
#[must_use]
pub const fn label(self) -> &'static str {
match self {
Self::IcpCanisterStatus => "IcpCanisterStatus",
Self::LocalDeploymentState => "LocalDeploymentState",
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ExpectedCanisterV1 {
pub role: String,
pub canister_id: Option<String>,
pub control_class: CanisterControlClassV1,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ObservedCanisterV1 {
pub canister_id: String,
pub role: Option<String>,
pub control_class: CanisterControlClassV1,
pub controllers: Vec<String>,
pub module_hash: Option<String>,
pub status: Option<String>,
pub root_trust_anchor: Option<String>,
pub canonical_embedded_config_digest: Option<String>,
pub role_assignment_source: Option<String>,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum CanisterControlClassV1 {
DeploymentControlled,
CanicManagedPool,
ExternallyImported,
JointlyControlled,
UserControlled,
UnknownUnsafe,
}
impl CanisterControlClassV1 {
#[must_use]
pub const fn label(self) -> &'static str {
match self {
Self::DeploymentControlled => "DeploymentControlled",
Self::CanicManagedPool => "CanicManagedPool",
Self::ExternallyImported => "ExternallyImported",
Self::JointlyControlled => "JointlyControlled",
Self::UserControlled => "UserControlled",
Self::UnknownUnsafe => "UnknownUnsafe",
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ExpectedPoolCanisterV1 {
pub pool: String,
pub canister_id: Option<String>,
pub role: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ObservedPoolCanisterV1 {
pub pool: String,
pub canister_id: String,
pub role: Option<String>,
pub control_class: CanisterControlClassV1,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct LocalDeploymentConfigV1 {
pub config_path: Option<String>,
pub raw_config_sha256: Option<String>,
pub canonical_embedded_config_sha256: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct VerifierReadinessExpectationV1 {
pub required: bool,
pub expected_role_epochs: Vec<RoleEpochExpectationV1>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct VerifierReadinessObservationV1 {
pub status: ObservationStatusV1,
pub role_epochs: Vec<RoleEpochObservationV1>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct RoleEpochExpectationV1 {
pub role: String,
pub minimum_epoch: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct RoleEpochObservationV1 {
pub role: String,
pub observed_epoch: Option<u64>,
pub status: ObservationStatusV1,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct DeploymentObservationGapV1 {
pub key: String,
pub description: String,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum ObservationStatusV1 {
NotObserved,
Observed,
Missing,
Inconclusive,
}
impl ObservationStatusV1 {
#[must_use]
pub const fn label(self) -> &'static str {
match self {
Self::NotObserved => "NotObserved",
Self::Observed => "Observed",
Self::Missing => "Missing",
Self::Inconclusive => "Inconclusive",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deployment_root_observation_source_owns_text_labels() {
assert_eq!(
DeploymentRootObservationSourceV1::IcpCanisterStatus.label(),
"IcpCanisterStatus"
);
assert_eq!(
DeploymentRootObservationSourceV1::LocalDeploymentState.label(),
"LocalDeploymentState"
);
}
#[test]
fn canister_control_class_owns_text_labels() {
assert_eq!(
CanisterControlClassV1::DeploymentControlled.label(),
"DeploymentControlled"
);
assert_eq!(
CanisterControlClassV1::CanicManagedPool.label(),
"CanicManagedPool"
);
assert_eq!(
CanisterControlClassV1::ExternallyImported.label(),
"ExternallyImported"
);
assert_eq!(
CanisterControlClassV1::JointlyControlled.label(),
"JointlyControlled"
);
assert_eq!(
CanisterControlClassV1::UserControlled.label(),
"UserControlled"
);
assert_eq!(
CanisterControlClassV1::UnknownUnsafe.label(),
"UnknownUnsafe"
);
}
#[test]
fn observation_status_owns_text_labels() {
assert_eq!(ObservationStatusV1::NotObserved.label(), "NotObserved");
assert_eq!(ObservationStatusV1::Observed.label(), "Observed");
assert_eq!(ObservationStatusV1::Missing.label(), "Missing");
assert_eq!(ObservationStatusV1::Inconclusive.label(), "Inconclusive");
}
}