routing/
lib.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5pub mod availability;
6pub mod bedrock;
7pub mod capability_source;
8pub mod component_instance;
9pub mod config;
10pub mod error;
11pub mod legacy_router;
12pub mod mapper;
13pub mod path;
14pub mod policy;
15pub mod resolving;
16pub mod rights;
17pub mod subdir;
18pub mod walk_state;
19
20use crate::bedrock::request_metadata::{
21    dictionary_metadata, directory_metadata, protocol_metadata, resolver_metadata, runner_metadata,
22    service_metadata,
23};
24use crate::capability_source::{
25    CapabilitySource, ComponentCapability, ComponentSource, InternalCapability, VoidSource,
26};
27use crate::component_instance::{
28    ComponentInstanceInterface, ResolvedInstanceInterface, WeakComponentInstanceInterface,
29};
30use crate::error::RoutingError;
31use crate::legacy_router::{
32    CapabilityVisitor, ErrorNotFoundFromParent, ErrorNotFoundInChild, ExposeVisitor, NoopVisitor,
33    OfferVisitor, RouteBundle, Sources,
34};
35use crate::mapper::DebugRouteMapper;
36use crate::rights::RightsWalker;
37use crate::walk_state::WalkState;
38use cm_rust::{
39    Availability, CapabilityTypeName, DebugProtocolRegistration, ExposeConfigurationDecl,
40    ExposeDecl, ExposeDeclCommon, ExposeDictionaryDecl, ExposeDirectoryDecl, ExposeProtocolDecl,
41    ExposeResolverDecl, ExposeRunnerDecl, ExposeServiceDecl, ExposeSource, ExposeTarget,
42    OfferConfigurationDecl, OfferDeclCommon, OfferDictionaryDecl, OfferDirectoryDecl,
43    OfferEventStreamDecl, OfferProtocolDecl, OfferResolverDecl, OfferRunnerDecl, OfferServiceDecl,
44    OfferSource, OfferStorageDecl, OfferTarget, RegistrationDeclCommon, RegistrationSource,
45    ResolverRegistration, RunnerRegistration, SourceName, StorageDecl, StorageDirectorySource,
46    UseConfigurationDecl, UseDecl, UseDeclCommon, UseDictionaryDecl, UseDirectoryDecl,
47    UseEventStreamDecl, UseProtocolDecl, UseRunnerDecl, UseServiceDecl, UseSource, UseStorageDecl,
48};
49use cm_types::{IterablePath, Name, RelativePath};
50use from_enum::FromEnum;
51use itertools::Itertools;
52use moniker::{ChildName, ExtendedMoniker, Moniker, MonikerError};
53use router_error::Explain;
54use sandbox::{
55    Capability, CapabilityBound, Connector, Data, Dict, DirConnector, Request, Routable, Router,
56    RouterResponse,
57};
58use std::fmt::Debug;
59use std::sync::Arc;
60use subdir::SubDir;
61use {fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_io as fio, zx_status as zx};
62
63pub use bedrock::dict_ext::{DictExt, GenericRouterResponse};
64pub use bedrock::lazy_get::LazyGet;
65pub use bedrock::weak_instance_token_ext::{WeakInstanceTokenExt, test_invalid_instance_token};
66pub use bedrock::with_porcelain::WithPorcelain;
67#[cfg(feature = "serde")]
68use serde::{Deserialize, Serialize};
69
70/// A request to route a capability, together with the data needed to do so.
71#[derive(Clone, Debug)]
72pub enum RouteRequest {
73    // Route a capability from an ExposeDecl.
74    ExposeDirectory(ExposeDirectoryDecl),
75    ExposeProtocol(ExposeProtocolDecl),
76    ExposeService(RouteBundle<ExposeServiceDecl>),
77    ExposeRunner(ExposeRunnerDecl),
78    ExposeResolver(ExposeResolverDecl),
79    ExposeConfig(ExposeConfigurationDecl),
80    ExposeDictionary(ExposeDictionaryDecl),
81
82    // Route a capability from a realm's environment.
83    Resolver(ResolverRegistration),
84
85    // Route the directory capability that backs a storage capability.
86    StorageBackingDirectory(StorageDecl),
87
88    // Route a capability from a UseDecl.
89    UseDirectory(UseDirectoryDecl),
90    UseEventStream(UseEventStreamDecl),
91    UseProtocol(UseProtocolDecl),
92    UseService(UseServiceDecl),
93    UseStorage(UseStorageDecl),
94    UseRunner(UseRunnerDecl),
95    UseConfig(UseConfigurationDecl),
96    UseDictionary(UseDictionaryDecl),
97
98    // Route a capability from an OfferDecl.
99    OfferDirectory(OfferDirectoryDecl),
100    OfferEventStream(OfferEventStreamDecl),
101    OfferProtocol(OfferProtocolDecl),
102    OfferService(RouteBundle<OfferServiceDecl>),
103    OfferStorage(OfferStorageDecl),
104    OfferRunner(OfferRunnerDecl),
105    OfferResolver(OfferResolverDecl),
106    OfferConfig(OfferConfigurationDecl),
107    OfferDictionary(OfferDictionaryDecl),
108}
109
110impl From<UseDecl> for RouteRequest {
111    fn from(decl: UseDecl) -> Self {
112        match decl {
113            UseDecl::Directory(decl) => Self::UseDirectory(decl),
114            UseDecl::Protocol(decl) => Self::UseProtocol(decl),
115            UseDecl::Service(decl) => Self::UseService(decl),
116            UseDecl::Storage(decl) => Self::UseStorage(decl),
117            UseDecl::EventStream(decl) => Self::UseEventStream(decl),
118            UseDecl::Runner(decl) => Self::UseRunner(decl),
119            UseDecl::Config(decl) => Self::UseConfig(decl),
120            UseDecl::Dictionary(decl) => Self::UseDictionary(decl),
121        }
122    }
123}
124
125impl RouteRequest {
126    pub fn from_expose_decls(exposes: Vec<&ExposeDecl>) -> Result<Self, RoutingError> {
127        let first_expose = exposes.first().expect("invalid empty expose list");
128        let first_type_name = CapabilityTypeName::from(*first_expose);
129        assert!(
130            exposes.iter().all(|e| {
131                let type_name: CapabilityTypeName = CapabilityTypeName::from(*e);
132                first_type_name == type_name && first_expose.target_name() == e.target_name()
133            }),
134            "invalid expose input: {:?}",
135            exposes
136        );
137        match first_expose {
138            ExposeDecl::Protocol(e) => {
139                assert!(exposes.len() == 1, "multiple exposes: {:?}", exposes);
140                Ok(Self::ExposeProtocol(e.clone()))
141            }
142            ExposeDecl::Service(_) => {
143                // Gather the exposes into a bundle. Services can aggregate, in which case
144                // multiple expose declarations map to one expose directory entry.
145                let exposes: Vec<_> = exposes
146                    .into_iter()
147                    .filter_map(|e| match e {
148                        cm_rust::ExposeDecl::Service(e) => Some(e.clone()),
149                        _ => None,
150                    })
151                    .collect();
152                Ok(Self::ExposeService(RouteBundle::from_exposes(exposes)))
153            }
154            ExposeDecl::Directory(e) => {
155                assert!(exposes.len() == 1, "multiple exposes");
156                Ok(Self::ExposeDirectory(e.clone()))
157            }
158            ExposeDecl::Runner(e) => {
159                assert!(exposes.len() == 1, "multiple exposes");
160                Ok(Self::ExposeRunner(e.clone()))
161            }
162            ExposeDecl::Resolver(e) => {
163                assert!(exposes.len() == 1, "multiple exposes");
164                Ok(Self::ExposeResolver(e.clone()))
165            }
166            ExposeDecl::Config(e) => {
167                assert!(exposes.len() == 1, "multiple exposes");
168                Ok(Self::ExposeConfig(e.clone()))
169            }
170            ExposeDecl::Dictionary(e) => {
171                assert!(exposes.len() == 1, "multiple exposes");
172                Ok(Self::ExposeDictionary(e.clone()))
173            }
174        }
175    }
176
177    /// Returns the availability of the RouteRequest if supported.
178    pub fn availability(&self) -> Option<Availability> {
179        use crate::RouteRequest::*;
180        match self {
181            UseDirectory(UseDirectoryDecl { availability, .. })
182            | UseEventStream(UseEventStreamDecl { availability, .. })
183            | UseProtocol(UseProtocolDecl { availability, .. })
184            | UseService(UseServiceDecl { availability, .. })
185            | UseConfig(UseConfigurationDecl { availability, .. })
186            | UseStorage(UseStorageDecl { availability, .. })
187            | UseDictionary(UseDictionaryDecl { availability, .. }) => Some(*availability),
188
189            ExposeDirectory(decl) => Some(*decl.availability()),
190            ExposeProtocol(decl) => Some(*decl.availability()),
191            ExposeService(decl) => Some(*decl.availability()),
192            ExposeRunner(decl) => Some(*decl.availability()),
193            ExposeResolver(decl) => Some(*decl.availability()),
194            ExposeConfig(decl) => Some(*decl.availability()),
195            ExposeDictionary(decl) => Some(*decl.availability()),
196
197            OfferRunner(decl) => Some(*decl.availability()),
198            OfferResolver(decl) => Some(*decl.availability()),
199            OfferDirectory(decl) => Some(*decl.availability()),
200            OfferEventStream(decl) => Some(*decl.availability()),
201            OfferProtocol(decl) => Some(*decl.availability()),
202            OfferConfig(decl) => Some(*decl.availability()),
203            OfferStorage(decl) => Some(*decl.availability()),
204            OfferDictionary(decl) => Some(*decl.availability()),
205
206            OfferService(_) | Resolver(_) | StorageBackingDirectory(_) | UseRunner(_) => None,
207        }
208    }
209}
210
211impl std::fmt::Display for RouteRequest {
212    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213        match self {
214            Self::ExposeDirectory(e) => {
215                write!(f, "directory `{}`", e.target_name)
216            }
217            Self::ExposeProtocol(e) => {
218                write!(f, "protocol `{}`", e.target_name)
219            }
220            Self::ExposeService(e) => {
221                write!(f, "service {:?}", e)
222            }
223            Self::ExposeRunner(e) => {
224                write!(f, "runner `{}`", e.target_name)
225            }
226            Self::ExposeResolver(e) => {
227                write!(f, "resolver `{}`", e.target_name)
228            }
229            Self::ExposeConfig(e) => {
230                write!(f, "config `{}`", e.target_name)
231            }
232            Self::ExposeDictionary(e) => {
233                write!(f, "dictionary `{}`", e.target_name)
234            }
235            Self::Resolver(r) => {
236                write!(f, "resolver `{}`", r.resolver)
237            }
238            Self::UseDirectory(u) => {
239                write!(f, "directory `{}`", u.source_name)
240            }
241            Self::UseProtocol(u) => {
242                write!(f, "protocol `{}`", u.source_name)
243            }
244            Self::UseService(u) => {
245                write!(f, "service `{}`", u.source_name)
246            }
247            Self::UseStorage(u) => {
248                write!(f, "storage `{}`", u.source_name)
249            }
250            Self::UseEventStream(u) => {
251                write!(f, "event stream `{}`", u.source_name)
252            }
253            Self::UseRunner(u) => {
254                write!(f, "runner `{}`", u.source_name)
255            }
256            Self::UseConfig(u) => {
257                write!(f, "config `{}`", u.source_name)
258            }
259            Self::UseDictionary(u) => {
260                write!(f, "dictionary `{}`", u.source_name)
261            }
262            Self::StorageBackingDirectory(u) => {
263                write!(f, "storage backing directory `{}`", u.backing_dir)
264            }
265            Self::OfferDirectory(o) => {
266                write!(f, "directory `{}`", o.target_name)
267            }
268            Self::OfferProtocol(o) => {
269                write!(f, "protocol `{}`", o.target_name)
270            }
271            Self::OfferService(o) => {
272                write!(f, "service {:?}", o)
273            }
274            Self::OfferEventStream(o) => {
275                write!(f, "event stream `{}`", o.target_name)
276            }
277            Self::OfferStorage(o) => {
278                write!(f, "storage `{}`", o.target_name)
279            }
280            Self::OfferResolver(o) => {
281                write!(f, "resolver `{}`", o.target_name)
282            }
283            Self::OfferRunner(o) => {
284                write!(f, "runner `{}`", o.target_name)
285            }
286            Self::OfferConfig(o) => {
287                write!(f, "config `{}`", o.target_name)
288            }
289            Self::OfferDictionary(o) => {
290                write!(f, "dictionary `{}`", o.target_name)
291            }
292        }
293    }
294}
295
296/// The data returned after successfully routing a capability to its source.
297#[derive(Debug)]
298pub struct RouteSource {
299    pub source: CapabilitySource,
300    pub relative_path: RelativePath,
301}
302
303impl RouteSource {
304    pub fn new(source: CapabilitySource) -> Self {
305        Self { source, relative_path: Default::default() }
306    }
307
308    pub fn new_with_relative_path(source: CapabilitySource, relative_path: RelativePath) -> Self {
309        Self { source, relative_path }
310    }
311}
312
313/// Performs a debug route from the `target` for the capability defined in `request`. The source of
314/// the route is returned if the route is valid, otherwise a routing error is returned.
315///
316/// If the capability is not allowed to be routed to the `target`, per the
317/// [`crate::model::policy::GlobalPolicyChecker`], then an error is returned.
318///
319/// This function will only be used for developer tools once the bedrock routing refactor has been
320/// completed, but for now it's the only way to route capabilities which are unsupported in
321/// bedrock.
322///
323/// For capabilities which are not supported in bedrock, the `mapper` is invoked on every step in
324/// the routing process and can be used to record the routing steps. Once all capabilities are
325/// supported in bedrock routing, the `mapper` argument will be removed.
326pub async fn route_capability<C>(
327    request: RouteRequest,
328    target: &Arc<C>,
329    mapper: &mut dyn DebugRouteMapper,
330) -> Result<RouteSource, RoutingError>
331where
332    C: ComponentInstanceInterface + 'static,
333{
334    match request {
335        // Route from an ExposeDecl
336        RouteRequest::ExposeDirectory(expose_dir_decl) => {
337            route_capability_inner::<DirConnector, _>(
338                &target.component_sandbox().await?.component_output.capabilities(),
339                &expose_dir_decl.target_name,
340                directory_metadata(
341                    expose_dir_decl.availability,
342                    expose_dir_decl.rights.and_then(|v| Some(v.into())),
343                    Some(expose_dir_decl.subdir.into()),
344                ),
345                target,
346            )
347            .await
348        }
349        RouteRequest::ExposeProtocol(expose_protocol_decl) => {
350            let sandbox = target.component_sandbox().await?;
351            let dictionary = match &expose_protocol_decl.target {
352                ExposeTarget::Parent => sandbox.component_output.capabilities(),
353                ExposeTarget::Framework => sandbox.component_output.framework(),
354            };
355            route_capability_inner::<Connector, _>(
356                &dictionary,
357                &expose_protocol_decl.target_name,
358                protocol_metadata(expose_protocol_decl.availability),
359                target,
360            )
361            .await
362        }
363        RouteRequest::ExposeService(expose_bundle) => {
364            let first_expose = expose_bundle.iter().next().expect("can't route empty bundle");
365            route_capability_inner::<DirConnector, _>(
366                &target.component_sandbox().await?.component_output.capabilities(),
367                first_expose.target_name(),
368                service_metadata(*first_expose.availability()),
369                target,
370            )
371            .await
372        }
373        RouteRequest::ExposeRunner(expose_runner_decl) => {
374            let sandbox = target.component_sandbox().await?;
375            let dictionary = match &expose_runner_decl.target {
376                ExposeTarget::Parent => sandbox.component_output.capabilities(),
377                ExposeTarget::Framework => sandbox.component_output.framework(),
378            };
379            route_capability_inner::<Connector, _>(
380                &dictionary,
381                &expose_runner_decl.target_name,
382                runner_metadata(Availability::Required),
383                target,
384            )
385            .await
386        }
387        RouteRequest::ExposeResolver(expose_resolver_decl) => {
388            let sandbox = target.component_sandbox().await?;
389            let dictionary = match &expose_resolver_decl.target {
390                ExposeTarget::Parent => sandbox.component_output.capabilities(),
391                ExposeTarget::Framework => sandbox.component_output.framework(),
392            };
393            route_capability_inner::<Connector, _>(
394                &dictionary,
395                &expose_resolver_decl.target_name,
396                resolver_metadata(Availability::Required),
397                target,
398            )
399            .await
400        }
401        RouteRequest::ExposeDictionary(expose_dictionary_decl) => {
402            let sandbox = target.component_sandbox().await?;
403            let dictionary = match &expose_dictionary_decl.target {
404                ExposeTarget::Parent => sandbox.component_output.capabilities(),
405                ExposeTarget::Framework => sandbox.component_output.framework(),
406            };
407            route_capability_inner::<Dict, _>(
408                &dictionary,
409                &expose_dictionary_decl.target_name,
410                dictionary_metadata(expose_dictionary_decl.availability),
411                target,
412            )
413            .await
414        }
415        RouteRequest::ExposeConfig(expose_config_decl) => {
416            route_config_from_expose(expose_config_decl, target, mapper).await
417        }
418
419        // Route a resolver or runner from an environment
420        RouteRequest::Resolver(resolver_registration) => {
421            let component_sandbox = target.component_sandbox().await?;
422            let source_dictionary = match &resolver_registration.source {
423                RegistrationSource::Parent => component_sandbox.component_input.capabilities(),
424                RegistrationSource::Self_ => component_sandbox.program_output_dict.clone(),
425                RegistrationSource::Child(static_name) => {
426                    let child_name = ChildName::parse(static_name).expect(
427                        "invalid child name, this should be prevented by manifest validation",
428                    );
429                    let child_component = target.lock_resolved_state().await?.get_child(&child_name).expect("resolver registration references nonexistent static child, this should be prevented by manifest validation");
430                    let child_sandbox = child_component.component_sandbox().await?;
431                    child_sandbox.component_output.capabilities().clone()
432                }
433            };
434            route_capability_inner::<Connector, _>(
435                &source_dictionary,
436                &resolver_registration.resolver,
437                resolver_metadata(Availability::Required),
438                target,
439            )
440            .await
441        }
442        // Route the backing directory for a storage capability
443        RouteRequest::StorageBackingDirectory(storage_decl) => {
444            route_storage_backing_directory(storage_decl, target, mapper).await
445        }
446
447        // Route from a UseDecl
448        RouteRequest::UseDirectory(use_directory_decl) => {
449            let subdir = match use_directory_decl.source {
450                UseSource::Self_ => None,
451                _ => Some(SubDir::from(use_directory_decl.subdir)),
452            };
453            route_capability_inner::<DirConnector, _>(
454                &target.component_sandbox().await?.program_input.namespace(),
455                &use_directory_decl.target_path,
456                directory_metadata(
457                    use_directory_decl.availability,
458                    Some(use_directory_decl.rights.into()),
459                    subdir,
460                ),
461                target,
462            )
463            .await
464        }
465        RouteRequest::UseEventStream(use_event_stream_decl) => {
466            route_event_stream(use_event_stream_decl, target, mapper).await
467        }
468        RouteRequest::UseProtocol(use_protocol_decl) => {
469            if let Some(target_path) = use_protocol_decl.target_path.as_ref() {
470                route_capability_inner::<Connector, _>(
471                    &target.component_sandbox().await?.program_input.namespace(),
472                    target_path,
473                    protocol_metadata(use_protocol_decl.availability),
474                    target,
475                )
476                .await
477            } else {
478                let numbered_handle = use_protocol_decl
479                    .numbered_handle
480                    .expect("validation guarantees numbered_handle is set");
481                let numbered_handle = Name::from(numbered_handle);
482                route_capability_inner::<Connector, _>(
483                    &target.component_sandbox().await?.program_input.numbered_handles(),
484                    &numbered_handle,
485                    protocol_metadata(use_protocol_decl.availability),
486                    target,
487                )
488                .await
489            }
490        }
491        RouteRequest::UseService(use_service_decl) => {
492            route_capability_inner::<DirConnector, _>(
493                &target.component_sandbox().await?.program_input.namespace(),
494                &use_service_decl.target_path,
495                service_metadata(use_service_decl.availability),
496                target,
497            )
498            .await
499        }
500        RouteRequest::UseStorage(use_storage_decl) => {
501            route_storage(use_storage_decl, target, mapper).await
502        }
503        RouteRequest::UseRunner(_use_runner_decl) => {
504            let router =
505                target.component_sandbox().await?.program_input.runner().expect("we have a use declaration for a runner but the program input dictionary has no runner, this should be impossible");
506            perform_route::<Connector, _>(router, runner_metadata(Availability::Required), target)
507                .await
508        }
509        RouteRequest::UseConfig(use_config_decl) => {
510            route_config(use_config_decl, target, mapper).await
511        }
512        RouteRequest::UseDictionary(use_dictionary_decl) => {
513            route_capability_inner::<Dict, _>(
514                &target.component_sandbox().await?.program_input.namespace(),
515                &use_dictionary_decl.target_path,
516                dictionary_metadata(use_dictionary_decl.availability),
517                target,
518            )
519            .await
520        }
521
522        // Route from a OfferDecl
523        RouteRequest::OfferProtocol(offer_protocol_decl) => {
524            let target_dictionary =
525                get_dictionary_for_offer_target(target, &offer_protocol_decl).await?;
526            let metadata = protocol_metadata(offer_protocol_decl.availability);
527            metadata
528                .insert(
529                    Name::new(crate::bedrock::with_policy_check::SKIP_POLICY_CHECKS).unwrap(),
530                    Capability::Data(Data::Uint64(1)),
531                )
532                .unwrap();
533            route_capability_inner::<Connector, _>(
534                &target_dictionary,
535                &offer_protocol_decl.target_name,
536                metadata,
537                target,
538            )
539            .await
540        }
541        RouteRequest::OfferDictionary(offer_dictionary_decl) => {
542            let target_dictionary =
543                get_dictionary_for_offer_target(target, &offer_dictionary_decl).await?;
544            let metadata = dictionary_metadata(offer_dictionary_decl.availability);
545            metadata
546                .insert(
547                    Name::new(crate::bedrock::with_policy_check::SKIP_POLICY_CHECKS).unwrap(),
548                    Capability::Data(Data::Uint64(1)),
549                )
550                .unwrap();
551            route_capability_inner::<Dict, _>(
552                &target_dictionary,
553                &offer_dictionary_decl.target_name,
554                metadata,
555                target,
556            )
557            .await
558        }
559        RouteRequest::OfferDirectory(offer_directory_decl) => {
560            let target_dictionary =
561                get_dictionary_for_offer_target(target, &offer_directory_decl).await?;
562            let metadata = directory_metadata(
563                offer_directory_decl.availability,
564                offer_directory_decl.rights.and_then(|v| Some(v.into())),
565                Some(offer_directory_decl.subdir.into()),
566            );
567            metadata
568                .insert(
569                    Name::new(crate::bedrock::with_policy_check::SKIP_POLICY_CHECKS).unwrap(),
570                    Capability::Data(Data::Uint64(1)),
571                )
572                .unwrap();
573            route_capability_inner::<DirConnector, _>(
574                &target_dictionary,
575                &offer_directory_decl.target_name,
576                metadata,
577                target,
578            )
579            .await
580        }
581        RouteRequest::OfferStorage(offer_storage_decl) => {
582            route_storage_from_offer(offer_storage_decl, target, mapper).await
583        }
584        RouteRequest::OfferService(offer_service_bundle) => {
585            let first_offer = offer_service_bundle.iter().next().expect("can't route empty bundle");
586            let target_dictionary = get_dictionary_for_offer_target(target, first_offer).await?;
587            let metadata = service_metadata(first_offer.availability);
588            metadata
589                .insert(
590                    Name::new(crate::bedrock::with_policy_check::SKIP_POLICY_CHECKS).unwrap(),
591                    Capability::Data(Data::Uint64(1)),
592                )
593                .unwrap();
594            route_capability_inner::<DirConnector, _>(
595                &target_dictionary,
596                &first_offer.target_name,
597                metadata,
598                target,
599            )
600            .await
601        }
602        RouteRequest::OfferEventStream(offer_event_stream_decl) => {
603            route_event_stream_from_offer(offer_event_stream_decl, target, mapper).await
604        }
605        RouteRequest::OfferRunner(offer_runner_decl) => {
606            let target_dictionary =
607                get_dictionary_for_offer_target(target, &offer_runner_decl).await?;
608            let metadata = runner_metadata(Availability::Required);
609            metadata
610                .insert(
611                    Name::new(crate::bedrock::with_policy_check::SKIP_POLICY_CHECKS).unwrap(),
612                    Capability::Data(Data::Uint64(1)),
613                )
614                .unwrap();
615            route_capability_inner::<Connector, _>(
616                &target_dictionary,
617                &offer_runner_decl.target_name,
618                metadata,
619                target,
620            )
621            .await
622        }
623        RouteRequest::OfferResolver(offer_resolver_decl) => {
624            let target_dictionary =
625                get_dictionary_for_offer_target(target, &offer_resolver_decl).await?;
626            let metadata = resolver_metadata(Availability::Required);
627            metadata
628                .insert(
629                    Name::new(crate::bedrock::with_policy_check::SKIP_POLICY_CHECKS).unwrap(),
630                    Capability::Data(Data::Uint64(1)),
631                )
632                .unwrap();
633            route_capability_inner::<Connector, _>(
634                &target_dictionary,
635                &offer_resolver_decl.target_name,
636                metadata,
637                target,
638            )
639            .await
640        }
641        RouteRequest::OfferConfig(offer) => route_config_from_offer(offer, target, mapper).await,
642    }
643}
644
645pub enum Never {}
646
647async fn route_capability_inner<T, C>(
648    dictionary: &Dict,
649    path: &impl IterablePath,
650    metadata: Dict,
651    target: &Arc<C>,
652) -> Result<RouteSource, RoutingError>
653where
654    C: ComponentInstanceInterface + 'static,
655    T: CapabilityBound + Debug,
656    Router<T>: TryFrom<Capability>,
657{
658    let router = dictionary
659        .get_capability(path)
660        .and_then(|c| Router::<T>::try_from(c).ok())
661        .ok_or_else(|| RoutingError::BedrockNotPresentInDictionary {
662            moniker: target.moniker().clone().into(),
663            name: path.iter_segments().join("/"),
664        })?;
665    perform_route::<T, C>(router, metadata, target).await
666}
667
668async fn perform_route<T, C>(
669    router: impl Routable<T>,
670    metadata: Dict,
671    target: &Arc<C>,
672) -> Result<RouteSource, RoutingError>
673where
674    C: ComponentInstanceInterface + 'static,
675    T: CapabilityBound + Debug,
676    Router<T>: TryFrom<Capability>,
677{
678    let request = Request { target: WeakComponentInstanceInterface::new(target).into(), metadata };
679    let data = match router.route(Some(request), true).await? {
680        RouterResponse::<T>::Debug(d) => d,
681        d => panic!("Debug route did not return a debug response: {d:?}"),
682    };
683    Ok(RouteSource::new(data.try_into().unwrap()))
684}
685
686async fn get_dictionary_for_offer_target<C, O>(
687    target: &Arc<C>,
688    offer: &O,
689) -> Result<Dict, RoutingError>
690where
691    C: ComponentInstanceInterface + 'static,
692    O: OfferDeclCommon,
693{
694    match offer.target() {
695        OfferTarget::Child(child_ref) if child_ref.collection.is_none() => {
696            // For static children we can find their inputs in the component's sandbox.
697            let child_input_name = Name::new(&child_ref.name)
698                .map_err(MonikerError::InvalidMonikerPart)
699                .expect("static child names must be short");
700            let target_sandbox = target.component_sandbox().await?;
701            let child_input = target_sandbox.child_inputs.get(&child_input_name).ok_or(
702                RoutingError::OfferFromChildInstanceNotFound {
703                    child_moniker: child_ref.clone().into(),
704                    moniker: target.moniker().clone(),
705                    capability_id: offer.target_name().clone().to_string(),
706                },
707            )?;
708            Ok(child_input.capabilities())
709        }
710        OfferTarget::Child(child_ref) => {
711            // Offers targeting dynamic children are trickier. The input to the dynamic
712            // child wasn't created as part of the parent's sandbox, and dynamic offers
713            // (like the one we're currently looking at) won't have their routes reflected
714            // in the general component input for the collection. To work around this, we
715            // look up the dynamic child from the parent and access its component input
716            // from there. Unlike the code path for static children, this causes the child
717            // to be resolved.
718            let child = target
719                .lock_resolved_state()
720                .await?
721                .get_child(&ChildName::from(child_ref.clone()))
722                .ok_or(RoutingError::OfferFromChildInstanceNotFound {
723                    child_moniker: child_ref.clone().into(),
724                    moniker: target.moniker().clone(),
725                    capability_id: offer.target_name().clone().to_string(),
726                })?;
727            Ok(child.component_sandbox().await?.component_input.capabilities())
728        }
729        OfferTarget::Collection(collection_name) => {
730            // Offers targeting collections start at the component input generated for the
731            // collection, which is in the component's sandbox.
732            let target_sandbox = target.component_sandbox().await?;
733            let collection_input = target_sandbox.collection_inputs.get(collection_name).ok_or(
734                RoutingError::OfferFromCollectionNotFound {
735                    collection: collection_name.to_string(),
736                    moniker: target.moniker().clone(),
737                    capability: offer.target_name().clone(),
738                },
739            )?;
740            Ok(collection_input.capabilities())
741        }
742        OfferTarget::Capability(dictionary_name) => {
743            // Offers targeting another capability are for adding the capability to a dictionary
744            // declared by the same component. These dictionaries are stored in the target's
745            // sandbox.
746            let target_sandbox = target.component_sandbox().await?;
747            let capability =
748                target_sandbox.declared_dictionaries.get(dictionary_name).ok().flatten().ok_or(
749                    RoutingError::BedrockNotPresentInDictionary {
750                        name: dictionary_name.to_string(),
751                        moniker: target.moniker().clone().into(),
752                    },
753                )?;
754            match capability {
755                Capability::Dictionary(dictionary) => Ok(dictionary),
756                other_type => Err(RoutingError::BedrockWrongCapabilityType {
757                    actual: other_type.debug_typename().to_string(),
758                    expected: "Dictionary".to_string(),
759                    moniker: target.moniker().clone().into(),
760                }),
761            }
762        }
763    }
764}
765
766/// Routes an EventStream capability from `target` to its source, starting from `offer_decl`.
767async fn route_event_stream_from_offer<C>(
768    offer_decl: OfferEventStreamDecl,
769    target: &Arc<C>,
770    mapper: &mut dyn DebugRouteMapper,
771) -> Result<RouteSource, RoutingError>
772where
773    C: ComponentInstanceInterface + 'static,
774{
775    let allowed_sources = Sources::new(CapabilityTypeName::EventStream).builtin();
776
777    let mut availability_visitor = offer_decl.availability;
778    let source = legacy_router::route_from_offer(
779        RouteBundle::from_offer(offer_decl.into()),
780        target.clone(),
781        allowed_sources,
782        &mut availability_visitor,
783        mapper,
784    )
785    .await?;
786    Ok(RouteSource::new(source))
787}
788
789async fn route_storage_from_offer<C>(
790    offer_decl: OfferStorageDecl,
791    target: &Arc<C>,
792    mapper: &mut dyn DebugRouteMapper,
793) -> Result<RouteSource, RoutingError>
794where
795    C: ComponentInstanceInterface + 'static,
796{
797    let mut availability_visitor = offer_decl.availability;
798    let allowed_sources = Sources::new(CapabilityTypeName::Storage).component();
799    let source = legacy_router::route_from_offer(
800        RouteBundle::from_offer(offer_decl.into()),
801        target.clone(),
802        allowed_sources,
803        &mut availability_visitor,
804        mapper,
805    )
806    .await?;
807    Ok(RouteSource::new(source))
808}
809
810async fn route_config_from_offer<C>(
811    offer_decl: OfferConfigurationDecl,
812    target: &Arc<C>,
813    mapper: &mut dyn DebugRouteMapper,
814) -> Result<RouteSource, RoutingError>
815where
816    C: ComponentInstanceInterface + 'static,
817{
818    let allowed_sources = Sources::new(CapabilityTypeName::Config).builtin().component();
819    let source = legacy_router::route_from_offer(
820        RouteBundle::from_offer(offer_decl.into()),
821        target.clone(),
822        allowed_sources,
823        &mut NoopVisitor::new(),
824        mapper,
825    )
826    .await?;
827    Ok(RouteSource::new(source))
828}
829
830async fn route_config_from_expose<C>(
831    expose_decl: ExposeConfigurationDecl,
832    target: &Arc<C>,
833    mapper: &mut dyn DebugRouteMapper,
834) -> Result<RouteSource, RoutingError>
835where
836    C: ComponentInstanceInterface + 'static,
837{
838    let allowed_sources = Sources::new(CapabilityTypeName::Config).component().capability();
839    let source = legacy_router::route_from_expose(
840        RouteBundle::from_expose(expose_decl.into()),
841        target.clone(),
842        allowed_sources,
843        &mut NoopVisitor::new(),
844        mapper,
845    )
846    .await?;
847
848    target.policy_checker().can_route_capability(&source, target.moniker())?;
849    Ok(RouteSource::new(source))
850}
851
852/// The accumulated state of routing a Directory capability.
853#[derive(Clone, Debug)]
854pub struct DirectoryState {
855    rights: WalkState<RightsWalker>,
856    pub subdir: RelativePath,
857    availability_state: Availability,
858}
859
860impl DirectoryState {
861    fn new(rights: RightsWalker, subdir: RelativePath, availability: &Availability) -> Self {
862        DirectoryState {
863            rights: WalkState::at(rights),
864            subdir,
865            availability_state: availability.clone(),
866        }
867    }
868
869    fn advance_with_offer(
870        &mut self,
871        moniker: &ExtendedMoniker,
872        offer: &OfferDirectoryDecl,
873    ) -> Result<(), RoutingError> {
874        self.availability_state =
875            availability::advance_with_offer(moniker, self.availability_state, offer)?;
876        self.advance(moniker, offer.rights.clone(), offer.subdir.clone())
877    }
878
879    fn advance_with_expose(
880        &mut self,
881        moniker: &ExtendedMoniker,
882        expose: &ExposeDirectoryDecl,
883    ) -> Result<(), RoutingError> {
884        self.availability_state =
885            availability::advance_with_expose(moniker, self.availability_state, expose)?;
886        self.advance(moniker, expose.rights.clone(), expose.subdir.clone())
887    }
888
889    fn advance(
890        &mut self,
891        moniker: &ExtendedMoniker,
892        rights: Option<fio::Operations>,
893        mut subdir: RelativePath,
894    ) -> Result<(), RoutingError> {
895        self.rights = self.rights.advance(rights.map(|r| RightsWalker::new(r, moniker.clone())))?;
896        if !subdir.extend(self.subdir.clone()) {
897            return Err(RoutingError::PathTooLong {
898                moniker: moniker.clone(),
899                path: format!("{}/{}", subdir, self.subdir),
900                keyword: "subdir".into(),
901            });
902        }
903        self.subdir = subdir;
904        Ok(())
905    }
906
907    fn finalize(
908        &mut self,
909        moniker: &ExtendedMoniker,
910        rights: RightsWalker,
911        mut subdir: RelativePath,
912    ) -> Result<(), RoutingError> {
913        self.rights = self.rights.finalize(Some(rights))?;
914        if !subdir.extend(self.subdir.clone()) {
915            return Err(RoutingError::PathTooLong {
916                moniker: moniker.clone(),
917                path: format!("{}/{}", subdir, self.subdir),
918                keyword: "subdir".into(),
919            });
920        }
921        self.subdir = subdir;
922        Ok(())
923    }
924}
925
926impl OfferVisitor for DirectoryState {
927    fn visit(
928        &mut self,
929        moniker: &ExtendedMoniker,
930        offer: &cm_rust::OfferDecl,
931    ) -> Result<(), RoutingError> {
932        match offer {
933            cm_rust::OfferDecl::Directory(dir) => match dir.source {
934                OfferSource::Framework => self.finalize(
935                    moniker,
936                    RightsWalker::new(fio::RX_STAR_DIR, moniker.clone()),
937                    dir.subdir.clone(),
938                ),
939                _ => self.advance_with_offer(moniker, dir),
940            },
941            _ => Ok(()),
942        }
943    }
944}
945
946impl ExposeVisitor for DirectoryState {
947    fn visit(
948        &mut self,
949        moniker: &ExtendedMoniker,
950        expose: &cm_rust::ExposeDecl,
951    ) -> Result<(), RoutingError> {
952        match expose {
953            cm_rust::ExposeDecl::Directory(dir) => match dir.source {
954                ExposeSource::Framework => self.finalize(
955                    moniker,
956                    RightsWalker::new(fio::RX_STAR_DIR, moniker.clone()),
957                    dir.subdir.clone(),
958                ),
959                _ => self.advance_with_expose(moniker, dir),
960            },
961            _ => Ok(()),
962        }
963    }
964}
965
966impl CapabilityVisitor for DirectoryState {
967    fn visit(
968        &mut self,
969        moniker: &ExtendedMoniker,
970        capability: &cm_rust::CapabilityDecl,
971    ) -> Result<(), RoutingError> {
972        match capability {
973            cm_rust::CapabilityDecl::Directory(dir) => self.finalize(
974                moniker,
975                RightsWalker::new(dir.rights, moniker.clone()),
976                Default::default(),
977            ),
978            _ => Ok(()),
979        }
980    }
981}
982
983/// Verifies that the given component is in the index if its `storage_id` is StaticInstanceId.
984/// - On success, Ok(()) is returned
985/// - RoutingError::ComponentNotInIndex is returned on failure.
986pub async fn verify_instance_in_component_id_index<C>(
987    source: &CapabilitySource,
988    instance: &Arc<C>,
989) -> Result<(), RoutingError>
990where
991    C: ComponentInstanceInterface + 'static,
992{
993    let (storage_decl, source_moniker) = match source {
994        CapabilitySource::Component(ComponentSource {
995            capability: ComponentCapability::Storage(storage_decl),
996            moniker,
997        }) => (storage_decl, moniker.clone()),
998        CapabilitySource::Void(VoidSource { .. }) => return Ok(()),
999        _ => unreachable!("unexpected storage source"),
1000    };
1001
1002    if storage_decl.storage_id == fdecl::StorageId::StaticInstanceId
1003        && instance.component_id_index().id_for_moniker(instance.moniker()).is_none()
1004    {
1005        return Err(RoutingError::ComponentNotInIdIndex {
1006            source_moniker,
1007            target_name: instance.moniker().leaf().map(Into::into),
1008        });
1009    }
1010    Ok(())
1011}
1012
1013/// Routes a Storage capability from `target` to its source, starting from `use_decl`.
1014/// Returns the StorageDecl and the storage component's instance.
1015pub async fn route_to_storage_decl<C>(
1016    use_decl: UseStorageDecl,
1017    target: &Arc<C>,
1018    mapper: &mut dyn DebugRouteMapper,
1019) -> Result<CapabilitySource, RoutingError>
1020where
1021    C: ComponentInstanceInterface + 'static,
1022{
1023    let mut availability_visitor = use_decl.availability;
1024    let allowed_sources = Sources::new(CapabilityTypeName::Storage).component();
1025    let source = legacy_router::route_from_use(
1026        use_decl.into(),
1027        target.clone(),
1028        allowed_sources,
1029        &mut availability_visitor,
1030        mapper,
1031    )
1032    .await?;
1033    Ok(source)
1034}
1035
1036/// Routes a Storage capability from `target` to its source, starting from `use_decl`.
1037/// The backing Directory capability is then routed to its source.
1038async fn route_storage<C>(
1039    use_decl: UseStorageDecl,
1040    target: &Arc<C>,
1041    mapper: &mut dyn DebugRouteMapper,
1042) -> Result<RouteSource, RoutingError>
1043where
1044    C: ComponentInstanceInterface + 'static,
1045{
1046    let source = route_to_storage_decl(use_decl, &target, mapper).await?;
1047    verify_instance_in_component_id_index(&source, target).await?;
1048    target.policy_checker().can_route_capability(&source, target.moniker())?;
1049    Ok(RouteSource::new(source))
1050}
1051
1052/// Routes the backing Directory capability of a Storage capability from `target` to its source,
1053/// starting from `storage_decl`.
1054async fn route_storage_backing_directory<C>(
1055    storage_decl: StorageDecl,
1056    target: &Arc<C>,
1057    mapper: &mut dyn DebugRouteMapper,
1058) -> Result<RouteSource, RoutingError>
1059where
1060    C: ComponentInstanceInterface + 'static,
1061{
1062    // Storage rights are always READ+WRITE.
1063    let mut state = DirectoryState::new(
1064        RightsWalker::new(fio::RW_STAR_DIR, target.moniker().clone()),
1065        Default::default(),
1066        &Availability::Required,
1067    );
1068    let allowed_sources = Sources::new(CapabilityTypeName::Directory).component().namespace();
1069    let source = legacy_router::route_from_registration(
1070        StorageDeclAsRegistration::from(storage_decl.clone()),
1071        target.clone(),
1072        allowed_sources,
1073        &mut state,
1074        mapper,
1075    )
1076    .await?;
1077
1078    target.policy_checker().can_route_capability(&source, target.moniker())?;
1079
1080    Ok(RouteSource::new_with_relative_path(source, state.subdir))
1081}
1082
1083/// Finds a Configuration capability that matches the given use.
1084async fn route_config<C>(
1085    use_decl: UseConfigurationDecl,
1086    target: &Arc<C>,
1087    mapper: &mut dyn DebugRouteMapper,
1088) -> Result<RouteSource, RoutingError>
1089where
1090    C: ComponentInstanceInterface + 'static,
1091{
1092    let allowed_sources = Sources::new(CapabilityTypeName::Config).component().capability();
1093    let mut availability_visitor = use_decl.availability().clone();
1094    let source = legacy_router::route_from_use(
1095        use_decl.clone().into(),
1096        target.clone(),
1097        allowed_sources,
1098        &mut availability_visitor,
1099        mapper,
1100    )
1101    .await;
1102    // If the route was not found, but it's a transitional availability then return
1103    // a successful Void capability.
1104    let source = match source {
1105        Ok(s) => s,
1106        Err(e) => {
1107            if *use_decl.availability() == Availability::Transitional
1108                && e.as_zx_status() == zx::Status::NOT_FOUND
1109            {
1110                CapabilitySource::Void(VoidSource {
1111                    capability: InternalCapability::Config(use_decl.source_name),
1112                    moniker: target.moniker().clone(),
1113                })
1114            } else {
1115                return Err(e);
1116            }
1117        }
1118    };
1119
1120    target.policy_checker().can_route_capability(&source, target.moniker())?;
1121    Ok(RouteSource::new(source))
1122}
1123
1124/// Routes an EventStream capability from `target` to its source, starting from `use_decl`.
1125///
1126/// If the capability is not allowed to be routed to the `target`, per the
1127/// [`crate::model::policy::GlobalPolicyChecker`], then an error is returned.
1128pub async fn route_event_stream<C>(
1129    use_decl: UseEventStreamDecl,
1130    target: &Arc<C>,
1131    mapper: &mut dyn DebugRouteMapper,
1132) -> Result<RouteSource, RoutingError>
1133where
1134    C: ComponentInstanceInterface + 'static,
1135{
1136    let allowed_sources = Sources::new(CapabilityTypeName::EventStream).builtin();
1137    let mut availability_visitor = use_decl.availability;
1138    let source = legacy_router::route_from_use(
1139        use_decl.into(),
1140        target.clone(),
1141        allowed_sources,
1142        &mut availability_visitor,
1143        mapper,
1144    )
1145    .await?;
1146    target.policy_checker().can_route_capability(&source, target.moniker())?;
1147    Ok(RouteSource::new(source))
1148}
1149
1150/// Intermediate type to masquerade as Registration-style routing start point for the storage
1151/// backing directory capability.
1152#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1153#[derive(Debug, Clone, PartialEq, Eq)]
1154pub struct StorageDeclAsRegistration {
1155    source: RegistrationSource,
1156    name: Name,
1157}
1158
1159impl From<StorageDecl> for StorageDeclAsRegistration {
1160    fn from(decl: StorageDecl) -> Self {
1161        Self {
1162            name: decl.backing_dir,
1163            source: match decl.source {
1164                StorageDirectorySource::Parent => RegistrationSource::Parent,
1165                StorageDirectorySource::Self_ => RegistrationSource::Self_,
1166                StorageDirectorySource::Child(child) => RegistrationSource::Child(child),
1167            },
1168        }
1169    }
1170}
1171
1172impl SourceName for StorageDeclAsRegistration {
1173    fn source_name(&self) -> &Name {
1174        &self.name
1175    }
1176}
1177
1178impl RegistrationDeclCommon for StorageDeclAsRegistration {
1179    const TYPE: &'static str = "storage";
1180
1181    fn source(&self) -> &RegistrationSource {
1182        &self.source
1183    }
1184}
1185
1186/// An umbrella type for registration decls, making it more convenient to record route
1187/// maps for debug use.
1188#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1189#[derive(FromEnum, Debug, Clone, PartialEq, Eq)]
1190pub enum RegistrationDecl {
1191    Resolver(ResolverRegistration),
1192    Runner(RunnerRegistration),
1193    Debug(DebugProtocolRegistration),
1194    Directory(StorageDeclAsRegistration),
1195}
1196
1197impl From<&RegistrationDecl> for cm_rust::CapabilityTypeName {
1198    fn from(registration: &RegistrationDecl) -> Self {
1199        match registration {
1200            RegistrationDecl::Directory(_) => Self::Directory,
1201            RegistrationDecl::Resolver(_) => Self::Resolver,
1202            RegistrationDecl::Runner(_) => Self::Runner,
1203            RegistrationDecl::Debug(_) => Self::Protocol,
1204        }
1205    }
1206}
1207
1208// Error trait impls
1209
1210impl ErrorNotFoundFromParent for cm_rust::UseDecl {
1211    fn error_not_found_from_parent(moniker: Moniker, capability_name: Name) -> RoutingError {
1212        RoutingError::UseFromParentNotFound { moniker, capability_id: capability_name.into() }
1213    }
1214}
1215
1216impl ErrorNotFoundFromParent for cm_rust::DebugProtocolRegistration {
1217    fn error_not_found_from_parent(moniker: Moniker, capability_name: Name) -> RoutingError {
1218        RoutingError::EnvironmentFromParentNotFound {
1219            moniker,
1220            capability_name,
1221            capability_type: cm_rust::CapabilityTypeName::Protocol.to_string(),
1222        }
1223    }
1224}
1225
1226impl ErrorNotFoundInChild for cm_rust::DebugProtocolRegistration {
1227    fn error_not_found_in_child(
1228        moniker: Moniker,
1229        child_moniker: ChildName,
1230        capability_name: Name,
1231    ) -> RoutingError {
1232        RoutingError::EnvironmentFromChildExposeNotFound {
1233            moniker,
1234            child_moniker,
1235            capability_name,
1236            capability_type: cm_rust::CapabilityTypeName::Protocol.to_string(),
1237        }
1238    }
1239}
1240
1241impl ErrorNotFoundInChild for cm_rust::UseDecl {
1242    fn error_not_found_in_child(
1243        moniker: Moniker,
1244        child_moniker: ChildName,
1245        capability_name: Name,
1246    ) -> RoutingError {
1247        RoutingError::UseFromChildExposeNotFound {
1248            child_moniker,
1249            moniker,
1250            capability_id: capability_name.into(),
1251        }
1252    }
1253}
1254
1255impl ErrorNotFoundInChild for cm_rust::ExposeDecl {
1256    fn error_not_found_in_child(
1257        moniker: Moniker,
1258        child_moniker: ChildName,
1259        capability_name: Name,
1260    ) -> RoutingError {
1261        RoutingError::ExposeFromChildExposeNotFound {
1262            moniker,
1263            child_moniker,
1264            capability_id: capability_name.into(),
1265        }
1266    }
1267}
1268
1269impl ErrorNotFoundInChild for cm_rust::OfferDecl {
1270    fn error_not_found_in_child(
1271        moniker: Moniker,
1272        child_moniker: ChildName,
1273        capability_name: Name,
1274    ) -> RoutingError {
1275        RoutingError::OfferFromChildExposeNotFound {
1276            moniker,
1277            child_moniker,
1278            capability_id: capability_name.into(),
1279        }
1280    }
1281}
1282
1283impl ErrorNotFoundFromParent for cm_rust::OfferDecl {
1284    fn error_not_found_from_parent(moniker: Moniker, capability_name: Name) -> RoutingError {
1285        RoutingError::OfferFromParentNotFound { moniker, capability_id: capability_name.into() }
1286    }
1287}
1288
1289impl ErrorNotFoundInChild for StorageDeclAsRegistration {
1290    fn error_not_found_in_child(
1291        moniker: Moniker,
1292        child_moniker: ChildName,
1293        capability_name: Name,
1294    ) -> RoutingError {
1295        RoutingError::StorageFromChildExposeNotFound {
1296            moniker,
1297            child_moniker,
1298            capability_id: capability_name.into(),
1299        }
1300    }
1301}
1302
1303impl ErrorNotFoundFromParent for StorageDeclAsRegistration {
1304    fn error_not_found_from_parent(moniker: Moniker, capability_name: Name) -> RoutingError {
1305        RoutingError::StorageFromParentNotFound { moniker, capability_id: capability_name.into() }
1306    }
1307}
1308
1309impl ErrorNotFoundFromParent for RunnerRegistration {
1310    fn error_not_found_from_parent(moniker: Moniker, capability_name: Name) -> RoutingError {
1311        RoutingError::UseFromEnvironmentNotFound {
1312            moniker,
1313            capability_name,
1314            capability_type: "runner".to_string(),
1315        }
1316    }
1317}
1318
1319impl ErrorNotFoundInChild for RunnerRegistration {
1320    fn error_not_found_in_child(
1321        moniker: Moniker,
1322        child_moniker: ChildName,
1323        capability_name: Name,
1324    ) -> RoutingError {
1325        RoutingError::EnvironmentFromChildExposeNotFound {
1326            moniker,
1327            child_moniker,
1328            capability_name,
1329            capability_type: "runner".to_string(),
1330        }
1331    }
1332}
1333
1334impl ErrorNotFoundFromParent for ResolverRegistration {
1335    fn error_not_found_from_parent(moniker: Moniker, capability_name: Name) -> RoutingError {
1336        RoutingError::EnvironmentFromParentNotFound {
1337            moniker,
1338            capability_name,
1339            capability_type: "resolver".to_string(),
1340        }
1341    }
1342}
1343
1344impl ErrorNotFoundInChild for ResolverRegistration {
1345    fn error_not_found_in_child(
1346        moniker: Moniker,
1347        child_moniker: ChildName,
1348        capability_name: Name,
1349    ) -> RoutingError {
1350        RoutingError::EnvironmentFromChildExposeNotFound {
1351            moniker,
1352            child_moniker,
1353            capability_name,
1354            capability_type: "resolver".to_string(),
1355        }
1356    }
1357}