ic_auth/portable/grants.rs
1//! Immutable structural admission for host-selected portable authority grants.
2use crate::certificate_issuance::{GrantValidationError, validate_grants};
3use ic_auth_protocol_types::DelegatedRoleGrant;
4
5/// Owned canonical grants admitted to the portable limits once, before use.
6/// This establishes shape only, never enrollment, provenance or authorization.
7/// Hosts must select the current protected set and advance their generation
8/// atomically with authority changes. Clock, revocation and scope checks still
9/// run for every operation. Construct a fresh value after decoding configuration
10/// or restoring it from storage; this type has no unchecked deserializer.
11///
12/// Read access cannot invalidate admitted ordering or grammar:
13/// ```compile_fail
14/// use ic_auth::portable::ValidatedGrants;
15/// fn change(grants: &mut ValidatedGrants) {
16/// grants.as_slice()[0].scopes.clear();
17/// }
18/// ```
19#[derive(Clone, Debug, Eq, PartialEq)]
20pub struct ValidatedGrants(Vec<DelegatedRoleGrant>);
21
22impl ValidatedGrants {
23 /// Admit nonempty, strictly ordered role/scope grants without normalization.
24 /// Refuse more than 16 roles or 32 scopes per role, empty scope sets and
25 /// invalid scope labels through the canonical grant validator.
26 pub fn new(grants: Vec<DelegatedRoleGrant>) -> Result<Self, GrantValidationError> {
27 validate_grants(
28 &grants,
29 crate::limits::MAX_GRANTS,
30 crate::limits::MAX_SCOPES_PER_GRANT,
31 )?;
32 Ok(Self(grants))
33 }
34
35 pub fn as_slice(&self) -> &[DelegatedRoleGrant] {
36 &self.0
37 }
38
39 /// Consume structural evidence before editing or projecting the raw grants.
40 /// Reconstruct through `new` before using edited grants as authority again.
41 pub fn into_vec(self) -> Vec<DelegatedRoleGrant> {
42 self.0
43 }
44}