Skip to main content

canic_core/ids/fleet_admission/
mod.rs

1//! Module: ids::fleet_admission
2//!
3//! Responsibility: carry layer-neutral Fleet admission authority and selector identities.
4//! Does not own: validation, hashing, persistence, mutation, or endpoint enforcement.
5//! Boundary: protected host plans and canister protocols share these exact version-1 shapes.
6
7use super::{
8    ComponentInstanceId, ComponentSpecId, FleetBinding, FleetCoordinatorBinding,
9    ManagedCanisterBinding, SubnetId,
10};
11use candid::{CandidType, Principal};
12use serde::{Deserialize, Serialize};
13
14/// Maintained generation and wire schema for Fleet admission authority.
15pub const FLEET_ADMISSION_SCHEMA_VERSION: u16 = 1;
16/// First policy generation installed into a fresh Fleet.
17pub const FLEET_ADMISSION_INITIAL_GENERATION: u64 = 1;
18/// Maximum Principals in the Fleet-wide admission set.
19pub const MAX_FLEET_ADMISSION_PRINCIPALS: usize = 256;
20/// Maximum narrower selectors retained by one policy.
21pub const MAX_FLEET_ADMISSION_RULES: usize = 32;
22/// Maximum Principal references across every narrower rule.
23pub const MAX_FLEET_ADMISSION_RULE_PRINCIPAL_REFERENCES: usize = 128;
24/// Maximum encoded managed projection record retained at memory ID 61.
25pub const MAX_FLEET_ADMISSION_PROJECTION_RECORD_BYTES: u32 = 32 * 1024;
26/// Maximum Principals returned by one protected local projection page.
27pub const MAX_FLEET_ADMISSION_PROJECTION_PAGE: u64 = 128;
28
29/// Exact policy scope selected by protected input or a controller mutation.
30#[derive(CandidType, Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
31pub enum FleetAdmissionSelector {
32    #[serde(rename = "fleet")]
33    Fleet,
34    #[serde(rename = "component_spec")]
35    ComponentSpec(ComponentSpecId),
36    #[serde(rename = "component_instance")]
37    ComponentInstance(ComponentInstanceId),
38    #[serde(rename = "fleet_subnet_root")]
39    FleetSubnetRoot(SubnetId),
40}
41
42/// One canonical narrower admission rule.
43#[derive(CandidType, Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
44#[serde(deny_unknown_fields)]
45pub struct FleetAdmissionRule {
46    pub selector: FleetAdmissionSelector,
47    pub principals: Vec<Principal>,
48}
49
50/// Protected generation-one policy before a fresh Fleet identity exists.
51#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
52#[serde(deny_unknown_fields)]
53pub struct FleetAdmissionPolicyTemplate {
54    pub schema_version: u16,
55    pub fleet_principals: Vec<Principal>,
56    pub rules: Vec<FleetAdmissionRule>,
57    pub template_digest: [u8; 32],
58}
59
60/// One exact Coordinator-owned Fleet admission policy.
61#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
62#[serde(deny_unknown_fields)]
63pub struct FleetAdmissionPolicy {
64    pub schema_version: u16,
65    pub fleet: FleetBinding,
66    pub generation: u64,
67    pub fleet_principals: Vec<Principal>,
68    pub rules: Vec<FleetAdmissionRule>,
69    pub policy_digest: [u8; 32],
70}
71
72/// Exact managed target facts used to derive one effective local projection.
73#[derive(Clone, Debug, Eq, PartialEq)]
74pub struct FleetAdmissionTarget {
75    pub component_spec: ComponentSpecId,
76    pub component_instance: Option<ComponentInstanceId>,
77    pub fleet_subnet_root: SubnetId,
78}
79
80/// One complete target-bound local enforcement projection.
81#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
82#[serde(deny_unknown_fields)]
83pub struct FleetAdmissionProjection {
84    pub schema_version: u16,
85    pub authority: FleetCoordinatorBinding,
86    pub target: ManagedCanisterBinding,
87    pub generation: u64,
88    pub policy_digest: [u8; 32],
89    pub projection_digest: [u8; 32],
90    pub principals: Vec<Principal>,
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96    use candid::{Decode, Encode};
97
98    #[test]
99    fn selector_candid_labels_round_trip_through_serde() {
100        let encoded = Encode!(&FleetAdmissionSelector::Fleet).expect("encode Fleet selector");
101        let decoded = Decode!(&encoded, FleetAdmissionSelector).expect("decode Fleet selector");
102        assert_eq!(decoded, FleetAdmissionSelector::Fleet);
103    }
104}