ic_memory/policy.rs
1use crate::{key::StableKey, slot::MemoryManagerSlot};
2use serde::Serialize;
3
4///
5/// PolicyIdentity
6///
7/// Host-issued token binding one prepared runtime bootstrap policy configuration.
8///
9/// All 32-byte values are valid. Hosts choose a stable token and change it when
10/// policy semantics or effective configuration change. Names, versions, hashing
11/// and fallible configuration preparation stay with the host. The token is an
12/// equality binding, not authentication or proof that a policy is correct.
13/// It is retained in memory and serialized for diagnostics, never persisted
14/// in the allocation ledger. Diagnostic JSON contains a 32-element byte array.
15///
16
17#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
18#[serde(transparent)]
19pub struct PolicyIdentity([u8; 32]);
20
21impl PolicyIdentity {
22 /// Construct a token from the host's complete policy identity bytes.
23 #[must_use]
24 pub const fn new(bytes: [u8; 32]) -> Self {
25 Self(bytes)
26 }
27
28 /// Borrow the exact identity bytes used for equality and diagnostics.
29 #[must_use]
30 pub const fn as_bytes(&self) -> &[u8; 32] {
31 &self.0
32 }
33}
34
35///
36/// RuntimeBootstrapPolicy
37///
38/// Host policy for recovered admission, allocation checks and runtime identity.
39///
40/// The runtime admits host grants and pool eligibility before calling the
41/// allocation check for each external declaration. Governance stays private;
42/// historical ownership checks still apply to every declaration.
43///
44/// [`crate::MemoryRuntime`] binds its successful bootstrap to this identity.
45/// Repeated bootstrap is idempotent only when the caller supplies the same
46/// sealed declaration snapshot and the same policy identity. Implementations
47/// should change the identity whenever policy configuration or semantics
48/// change. Hosts derive the token from all effective configuration and prepare
49/// any fallible policy setup before calling the runtime. Labels, versions and
50/// hashing algorithms belong to the host; this crate compares the token bytes.
51///
52
53pub trait RuntimeBootstrapPolicy {
54 /// Policy error type.
55 type Error;
56
57 /// Validate one resolved stable-key and allocation-slot claim.
58 /// The runtime checks host grants and pool eligibility before this callback;
59 /// historical ownership checks follow it. Governance bypasses this callback.
60 fn validate_allocation(
61 &self,
62 key: &StableKey,
63 slot: &MemoryManagerSlot,
64 ) -> Result<(), Self::Error>;
65
66 /// Admit recovered identity and complete declarations before resolution.
67 ///
68 /// Runs once per cold bootstrap attempt after validated recovery. Warm
69 /// bootstrap/adoption does not replay it. The default selects no historical
70 /// keys. Hosts compose generated consumers here under their existing policy
71 /// and bucket profile. Include these semantics in the policy identity.
72 fn prepare_bootstrap(
73 &self,
74 _admission: &mut crate::BootstrapAdmission<'_>,
75 ) -> Result<(), Self::Error> {
76 Ok(())
77 }
78
79 /// Return the host-issued token for this prepared policy configuration.
80 fn runtime_bootstrap_identity(&self) -> PolicyIdentity;
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn policy_token_preserves_all_bytes_in_equality_and_diagnostics() {
89 let bytes = std::array::from_fn(|i| u8::try_from(i).unwrap());
90 let identity = PolicyIdentity::new(bytes);
91 assert_eq!(identity.as_bytes(), &bytes);
92 assert_eq!(
93 serde_json::to_value(identity).unwrap(),
94 serde_json::json!(bytes)
95 );
96 for index in 0..32 {
97 let mut changed = bytes;
98 changed[index] ^= 1;
99 assert_ne!(identity, PolicyIdentity::new(changed));
100 }
101 }
102}