canic_core/access/
policy.rs1use crate::{
2 Error, ThisError,
3 access::AccessError,
4 ops::{ic::Network, ic::build_network, storage::env::EnvOps},
5};
6
7#[derive(Debug, ThisError)]
12pub enum PolicyError {
13 #[error("this endpoint is only available on the prime subnet")]
14 NotPrimeSubnet,
15
16 #[error("this endpoint requires a build-time network (DFX_NETWORK) of either 'ic' or 'local'")]
17 BuildNetworkUnknown,
18
19 #[error(
20 "this endpoint is only available when built for '{expected}' (DFX_NETWORK), but was built for '{actual}'"
21 )]
22 BuildNetworkMismatch { expected: Network, actual: Network },
23}
24
25impl From<PolicyError> for Error {
26 fn from(err: PolicyError) -> Self {
27 AccessError::PolicyError(err).into()
28 }
29}
30
31#[allow(clippy::unused_async)]
36pub async fn is_prime_subnet() -> Result<(), Error> {
37 if EnvOps::is_prime_subnet() {
38 Ok(())
39 } else {
40 Err(PolicyError::NotPrimeSubnet.into())
41 }
42}
43
44#[allow(clippy::unused_async)]
50pub async fn build_network_ic() -> Result<(), Error> {
51 check_build_network(Network::Ic).map_err(Into::into)
52}
53
54#[allow(clippy::unused_async)]
60pub async fn build_network_local() -> Result<(), Error> {
61 check_build_network(Network::Local).map_err(Into::into)
62}
63
64pub(crate) fn check_build_network(expected: Network) -> Result<(), PolicyError> {
69 let actual = build_network();
70
71 match actual {
72 Some(actual) if actual == expected => Ok(()),
73 Some(actual) => Err(PolicyError::BuildNetworkMismatch { expected, actual }),
74 None => Err(PolicyError::BuildNetworkUnknown),
75 }
76}
77
78#[cfg(test)]
83mod tests {
84 use super::*;
85
86 fn check(expected: Network, actual: Option<Network>) -> Result<(), PolicyError> {
87 match actual {
89 Some(actual) if actual == expected => Ok(()),
90 Some(actual) => Err(PolicyError::BuildNetworkMismatch { expected, actual }),
91 None => Err(PolicyError::BuildNetworkUnknown),
92 }
93 }
94
95 #[test]
96 fn build_network_matches_expected() {
97 assert!(check(Network::Ic, Some(Network::Ic)).is_ok());
98 assert!(check(Network::Local, Some(Network::Local)).is_ok());
99 }
100
101 #[test]
102 fn build_network_mismatch_errors() {
103 let err = check(Network::Ic, Some(Network::Local)).unwrap_err();
104
105 match err {
106 PolicyError::BuildNetworkMismatch { expected, actual } => {
107 assert_eq!(expected, Network::Ic);
108 assert_eq!(actual, Network::Local);
109 }
110 _ => panic!("expected BuildNetworkMismatch"),
111 }
112 }
113
114 #[test]
115 fn build_network_unknown_errors() {
116 let err = check(Network::Ic, None).unwrap_err();
117 assert!(matches!(err, PolicyError::BuildNetworkUnknown));
118 }
119}