Skip to main content

canic_core/dto/
fleet_activation.rs

1//! Module: dto::fleet_activation
2//!
3//! Responsibility: carry Fleet activation identity and evidence across host/runtime boundaries.
4//! Does not own: validation, persistence, hashing, activation policy, or recovery transitions.
5//! Boundary: authoritative owners validate these passive shapes before storing or acting on them.
6
7use crate::ids::{FleetBinding, FleetKey, ReleaseBuildId};
8use candid::{CandidType, Principal};
9use serde::Deserialize;
10
11///
12/// CurrentRootInstallIdentity
13///
14
15/// Exact current-only identity accepted by a fresh or reinstalled Fleet root.
16#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
17pub struct CurrentRootInstallIdentity {
18    pub fleet: FleetBinding,
19    pub install_id: [u8; 32],
20    pub release_build_id: ReleaseBuildId,
21    pub expected_module_hash: Option<[u8; 32]>,
22}
23
24///
25/// FleetCascadeManifestEntry
26///
27
28#[derive(Clone, Debug, Eq, PartialEq)]
29pub struct FleetCascadeManifestEntry {
30    pub principal: Principal,
31    pub state_snapshot_hash: [u8; 32],
32    pub topology_snapshot_hash: [u8; 32],
33}
34
35///
36/// FleetCredentialGenerationRef
37///
38
39#[derive(Clone, Copy, Debug, Eq, PartialEq)]
40pub struct FleetCredentialGenerationRef {
41    pub generation: u64,
42    pub manifest_hash: [u8; 32],
43}
44
45///
46/// FleetCredentialManifestEntry
47///
48
49#[derive(Clone, Debug, Eq, PartialEq)]
50pub struct FleetCredentialManifestEntry {
51    pub root_issuer: Principal,
52    pub subject_canister: Principal,
53    pub not_before_ns: u64,
54    pub expires_at_ns: u64,
55    pub key_identity_hash: [u8; 32],
56    pub cert_hash: [u8; 32],
57    pub proof_hash: [u8; 32],
58    pub bundle_hash: [u8; 32],
59}
60
61///
62/// FleetCredentialManifest
63///
64
65#[derive(Clone, Debug, Eq, PartialEq)]
66pub struct FleetCredentialManifest {
67    pub fleet: FleetKey,
68    pub activation_id: [u8; 32],
69    pub generation: u64,
70    pub root_policy_set_hash: [u8; 32],
71    pub renewal_template_set_hash: [u8; 32],
72    pub entries: Vec<FleetCredentialManifestEntry>,
73}
74
75///
76/// FleetActivationIdentity
77///
78
79#[derive(Clone, Debug, Eq, PartialEq)]
80pub struct FleetActivationIdentity {
81    pub fleet: FleetBinding,
82    pub operation_id: [u8; 32],
83    pub release_build_id: ReleaseBuildId,
84}
85
86///
87/// FleetHostCanisterActivationEvidence
88///
89
90#[derive(Clone, Debug, Eq, PartialEq)]
91pub struct FleetHostCanisterActivationEvidence {
92    pub principal: Principal,
93    pub activation_evidence_hash: Option<[u8; 32]>,
94}
95
96///
97/// FleetActivationHostRecord
98///
99
100#[derive(Clone, Debug, Eq, PartialEq)]
101pub struct FleetActivationHostRecord {
102    pub identity: FleetActivationIdentity,
103    pub cascade_manifest: Option<Vec<FleetCascadeManifestEntry>>,
104    pub credential: Option<FleetCredentialGenerationRef>,
105    pub credential_manifest: Option<FleetCredentialManifest>,
106    pub canisters: Vec<FleetHostCanisterActivationEvidence>,
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112    use crate::ids::{AppId, CanonicalNetworkId, FleetId, FleetKey, ReleaseBuildNonce};
113
114    #[test]
115    fn current_root_install_identity_roundtrips_with_text_ids() {
116        let input = CurrentRootInstallIdentity {
117            fleet: FleetBinding {
118                fleet: FleetKey {
119                    network: CanonicalNetworkId::public_ic(),
120                    fleet_id: FleetId::from_generated_bytes([7; 32]),
121                },
122                app: AppId::from("toko"),
123            },
124            install_id: [8; 32],
125            release_build_id: ReleaseBuildId::from_nonce(ReleaseBuildNonce::from_random_bytes(
126                [9; 32],
127            )),
128            expected_module_hash: Some([10; 32]),
129        };
130
131        let bytes = candid::encode_one(&input).expect("encode current root install identity");
132        let decoded: CurrentRootInstallIdentity =
133            candid::decode_one(&bytes).expect("decode current root install identity");
134
135        assert_eq!(decoded, input);
136    }
137}