routing/bedrock/
with_policy_check.rs1use crate::capability_source::CapabilitySource;
6use crate::component_instance::{ComponentInstanceInterface, WeakExtendedInstanceInterface};
7use crate::error::{ComponentInstanceError, RoutingError};
8use crate::policy::GlobalPolicyChecker;
9use async_trait::async_trait;
10use moniker::ExtendedMoniker;
11use router_error::RouterError;
12#[cfg(not(target_os = "fuchsia"))]
13use runtime_capabilities::Capability;
14use runtime_capabilities::{CapabilityBound, Data, Request, Routable, Router, WeakInstanceToken};
15
16pub const SKIP_POLICY_CHECKS: &'static str = "skip_policy_checks";
34
35pub trait WithPolicyCheck {
36 fn with_policy_check<C: ComponentInstanceInterface + 'static>(
39 self,
40 capability_source: CapabilitySource,
41 policy_checker: GlobalPolicyChecker,
42 ) -> Self;
43}
44
45impl<T: CapabilityBound> WithPolicyCheck for Router<T> {
46 fn with_policy_check<C: ComponentInstanceInterface + 'static>(
47 self,
48 capability_source: CapabilitySource,
49 policy_checker: GlobalPolicyChecker,
50 ) -> Self {
51 Self::new(PolicyCheckRouter::<C, T>::new(capability_source, policy_checker, self))
52 }
53}
54
55pub struct PolicyCheckRouter<C: ComponentInstanceInterface + 'static, T: CapabilityBound> {
56 capability_source: CapabilitySource,
57 policy_checker: GlobalPolicyChecker,
58 router: Router<T>,
59 _phantom_data: std::marker::PhantomData<C>,
60}
61
62impl<C: ComponentInstanceInterface + 'static, T: CapabilityBound> PolicyCheckRouter<C, T> {
63 pub fn new(
64 capability_source: CapabilitySource,
65 policy_checker: GlobalPolicyChecker,
66 router: Router<T>,
67 ) -> Self {
68 Self {
69 capability_source,
70 policy_checker,
71 router,
72 _phantom_data: std::marker::PhantomData::<C>,
73 }
74 }
75
76 fn check_policy(
77 &self,
78 _request: &Option<Request>,
79 target_token: WeakInstanceToken,
80 ) -> Result<(), RouterError> {
81 #[cfg(not(target_os = "fuchsia"))]
82 if let Some(Capability::Data(runtime_capabilities::Data::Uint64(num))) = _request
83 .as_ref()
84 .ok_or_else(|| RouterError::InvalidArgs)?
85 .metadata
86 .get(&cm_types::Name::new(SKIP_POLICY_CHECKS).unwrap())
87 {
88 if num > 0 {
89 return Ok(());
90 }
91 }
92 let target = target_token
93 .inner
94 .as_any()
95 .downcast_ref::<WeakExtendedInstanceInterface<C>>()
96 .ok_or(RouterError::Unknown)?;
97 let ExtendedMoniker::ComponentInstance(moniker) = target.extended_moniker() else {
98 return Err(RoutingError::from(
99 ComponentInstanceError::ComponentManagerInstanceUnexpected {},
100 )
101 .into());
102 };
103 match self.policy_checker.can_route_capability(&self.capability_source, &moniker) {
104 Ok(()) => Ok(()),
105 Err(policy_error) => Err(RoutingError::PolicyError(policy_error).into()),
106 }
107 }
108}
109
110#[async_trait]
111impl<C: ComponentInstanceInterface + 'static, T: CapabilityBound> Routable<T>
112 for PolicyCheckRouter<C, T>
113{
114 async fn route(
115 &self,
116 request: Option<Request>,
117 target_token: WeakInstanceToken,
118 ) -> Result<Option<T>, RouterError> {
119 self.check_policy(&request, target_token.clone())?;
120 self.router.route(request, target_token).await
121 }
122
123 async fn route_debug(
124 &self,
125 request: Option<Request>,
126 target_token: WeakInstanceToken,
127 ) -> Result<Data, RouterError> {
128 self.check_policy(&request, target_token.clone())?;
129 self.router.route_debug(request, target_token).await
130 }
131}