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