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